Skip to content

Commit

Permalink
Add support for specifying the aspect ratio of the plot area (#88)
Browse files Browse the repository at this point in the history
A new `#:aspect-ratio` keyword argument was added to all the plot functions, allowing the user some more control over the plot area.
  • Loading branch information
alex-hhh authored Apr 3, 2021
1 parent 9189c8f commit c457141
Show file tree
Hide file tree
Showing 35 changed files with 311 additions and 45 deletions.
4 changes: 2 additions & 2 deletions plot-compat/plot/private/compat.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
(define bm (make-bitmap (ceiling width) (ceiling height)))
(define dc (make-object bitmap-dc% bm))
(define area (make-object 2d-plot-area%
bounds-rect x-ticks x-ticks y-ticks y-ticks '() dc 0 0 width height))
bounds-rect x-ticks x-ticks y-ticks y-ticks '() dc 0 0 width height #f))

(define data+axes (mix x-axis-data y-axis-data data))

Expand Down Expand Up @@ -214,7 +214,7 @@
(define bm (make-bitmap (ceiling width) (ceiling height)))
(define dc (make-object bitmap-dc% bm))
(define area (make-object 3d-plot-area%
bounds-rect x-ticks x-ticks y-ticks y-ticks z-ticks z-ticks '() dc 0 0 width height))
bounds-rect x-ticks x-ticks y-ticks y-ticks z-ticks z-ticks '() dc 0 0 width height #f))

(send area start-plot)
(send area start-renderer bounds-rect)
Expand Down
35 changes: 29 additions & 6 deletions plot-doc/plot/scribblings/params.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,29 @@ If @(racket #t), @(racket plot-file) and @(racket plot3d-file) open a dialog whe

@section{General Appearance}

@defparam[plot-aspect-ratio ratio (or/c (and/c rational? positive?) #f) #:value #f]{

Controls the aspect ratio of the plot area, independently from the width and
height of the entire plot.

When the aspect ratio is @(racket #f), the plot area fill fill the entire
area of the plot, leaving room only for the axis labels and title.

When an aspect ratio is a positive number, the plot area will maintain this
aspect ratio, possibly leaving empty areas around the plot.

This feature is useful when the aspect ratio needs to be maintained for the
plot output to look correct, for example when plotting a circle:

@interaction[#:eval plot-eval
(parameterize ([plot-aspect-ratio 1/1]
[plot-background "lightyellow"])
(plot (polar (lambda (t) 1)) #:width 400 #:height 200))]

@history[#:added "8.1"]

}

@deftogether[((defparam plot-title title (or/c string? #f) #:value #f)
(defparam plot-x-label label (or/c string? #f) #:value "x axis")
(defparam plot-y-label label (or/c string? #f) #:value "y axis")
Expand Down Expand Up @@ -117,7 +140,7 @@ For example, the value @racket['(columns 1 equal-size)] will place the legend en
top to bottom and all entries will have the same height. A value of @racket['(rows 2 'compact)] will
place legend entries horizontally on two rows -- this type of layout is useful when the legend is
placed at the top or bottom of the plot.

@history[#:added "7.9"]
}

Expand Down Expand Up @@ -333,11 +356,11 @@ The default width, pen color/width/style, and opacity used by @racket[error-bars
(defparam candlestick-line-width pen-width (>=/c 0) #:value 1)
(defparam candlestick-line-style pen-style plot-pen-style/c #:value 'solid)
(defparam candlestick-alpha alpha (real-in 0 1) #:value 2/3))]{
The default width, pen color/width/style, and opacity used by @racket[candlesticks]. Both the up (a candle whose
open value is lower than its close value) color and the down (a candle whose open value is higher than its close
value) color can be specified independently. The width parameter will be important to specify if your x-axis is
in units like days, weeks, or months. Because dates are actually represented as seconds from an epoch, your
width should take that into consideration. For example, a width of 86400 may be useful for x-axis values in days
The default width, pen color/width/style, and opacity used by @racket[candlesticks]. Both the up (a candle whose
open value is lower than its close value) color and the down (a candle whose open value is higher than its close
value) color can be specified independently. The width parameter will be important to specify if your x-axis is
in units like days, weeks, or months. Because dates are actually represented as seconds from an epoch, your
width should take that into consideration. For example, a width of 86400 may be useful for x-axis values in days
as there are 86400 seconds in a day. This candle will be exactly one day in width.
}

Expand Down
10 changes: 10 additions & 0 deletions plot-doc/plot/scribblings/plotting.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Each 3D plotting procedure behaves the same way as its corresponding 2D procedur
[#:title title (or/c string? pict? #f) (plot-title)]
[#:x-label x-label (or/c string? pict? #f) (plot-x-label)]
[#:y-label y-label (or/c string? pict? #f) (plot-y-label)]
[#:aspect-ratio aspect-ratio (or/c (and/c rational? positive?) #f) (plot-aspect-ratio)]
[#:legend-anchor legend-anchor legend-anchor/c (plot-legend-anchor)]
[#:out-file out-file (or/c path-string? output-port? #f) #f]
[#:out-kind out-kind plot-file-format/c 'auto]
Expand All @@ -51,6 +52,9 @@ When @(racket #:out-file) is given, @(racket plot) writes the plot to a file usi

When given, the @(racket x-min), @(racket x-max), @(racket y-min) and @(racket y-max) arguments determine the bounds of the plot, but not the bounds of the renderers. For example,

When given, the @(racket aspect-ratio) argument defines the aspect ratio of
the plot area, see @(racket plot-aspect-ratio) for more details.

@interaction[#:eval plot-eval
(plot (function (λ (x) (sin (* 4 x))) -1 1)
#:x-min -1.5 #:x-max 1.5 #:y-min -1.5 #:y-max 1.5)]
Expand All @@ -62,6 +66,7 @@ Please set the @(racket plot-foreground) and @(racket plot-background) parameter
The @(racket #:lncolor) keyword argument is also accepted for backward compatibility but deprecated. It does nothing.

@history[#:changed "7.9" "Added support for pictures for #:title, #:x-label and #:y-label. And to plot the legend outside the plot-area with #:legend-anchor"]
@history[#:changed "8.1" "Added #:aspect-ratio"]
}

@defproc[(plot3d [renderer-tree (treeof (or/c renderer3d? nonrenderer?))]
Expand All @@ -76,6 +81,7 @@ The @(racket #:lncolor) keyword argument is also accepted for backward compatibi
[#:x-label x-label (or/c string? pict? #f) (plot-x-label)]
[#:y-label y-label (or/c string? pict? #f) (plot-y-label)]
[#:z-label z-label (or/c string? pict? #f) (plot-z-label)]
[#:aspect-ratio aspect-ratio (or/c (and/c rational? positive?) #f) (plot-aspect-ratio)]
[#:legend-anchor legend-anchor legend-anchor/c (plot-legend-anchor)]
[#:out-file out-file (or/c path-string? output-port? #f) #f]
[#:out-kind out-kind plot-file-format/c 'auto]
Expand All @@ -88,13 +94,17 @@ When @(racket #:out-file) is given, @(racket plot3d) writes the plot to a file u

When given, the @(racket x-min), @(racket x-max), @(racket y-min), @(racket y-max), @(racket z-min) and @(racket z-max) arguments determine the bounds of the plot, but not the bounds of the renderers.

When given, the @(racket aspect-ratio) argument defines the aspect ratio of
the plot area, see @(racket plot-aspect-ratio) for more details.

@bold{Deprecated keywords.} The @(racket #:fgcolor) and @(racket #:bgcolor) keyword arguments are currently supported for backward compatibility, but may not be in the future.
Please set the @(racket plot-foreground) and @(racket plot-background) parameters instead of using these keyword arguments.
The @(racket #:lncolor) keyword argument is also accepted for backward compatibility but deprecated. It does nothing.

The @(racket #:az) and @(racket #:alt) keyword arguments are backward-compatible, deprecated aliases for @(racket #:angle) and @(racket #:altitude), respectively.

@history[#:changed "7.9" "Added support for pictures for #:title, #:x-label and #:y-label. And to plot the legend outside the plot-area with #:legend-anchor"]
@history[#:changed "8.1" "Added #:aspect-ratio"]
}

@defproc[(plot-snip [<plot-argument> <plot-argument-contract>] ...)
Expand Down
26 changes: 21 additions & 5 deletions plot-gui-lib/plot/private/gui/plot2d.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#:title (U String pict #f)
#:x-label (U String pict #f)
#:y-label (U String pict #f)
#:aspect-ratio (U Nonnegative-Real #f)
#:legend-anchor Legend-Anchor]
(Instance Snip%)))
(define (plot-snip renderer-tree
Expand All @@ -76,6 +77,7 @@
#:title [title (plot-title)]
#:x-label [x-label (plot-x-label)]
#:y-label [y-label (plot-y-label)]
#:aspect-ratio [aspect-ratio (plot-aspect-ratio)]
#:legend-anchor [legend-anchor (plot-legend-anchor)])
(define fail/kw (make-raise-keyword-error 'plot-snip))
(cond
Expand All @@ -89,6 +91,8 @@
[(and title (not (or (string? title) (pict? title)))) (fail/kw "#f, string or pict" '#:title title)]
[(and x-label (not (or (string? x-label) (pict? x-label)))) (fail/kw "#f, string or pict" '#:x-label x-label)]
[(and y-label (not (or (string? y-label) (pict? y-label)))) (fail/kw "#f, string or pict" '#:y-label y-label)]
[(and aspect-ratio (not (and (rational? aspect-ratio) (positive? aspect-ratio))))
(fail/kw "#f or positive real" '#:aspect-ratio aspect-ratio)]
[(not (legend-anchor/c legend-anchor)) (fail/kw "legend-anchor/c" '#:legend-anchor legend-anchor)])

(parameterize ([plot-title title]
Expand Down Expand Up @@ -116,7 +120,7 @@
(define new-area
(make-object 2d-plot-area%
bounds-rect x-ticks x-far-ticks y-ticks y-far-ticks legend
dc 0 0 width height))
dc 0 0 width height aspect-ratio))
(set! area new-area)
(plot-area new-area renderer-list))
(values bm area))
Expand All @@ -137,6 +141,7 @@
#:title (U String pict #f)
#:x-label (U String pict #f)
#:y-label (U String pict #f)
#:aspect-ratio (U Nonnegative-Real #f)
#:legend-anchor Legend-Anchor]
(Instance Frame%)))
(define (plot-frame renderer-tree
Expand All @@ -147,6 +152,7 @@
#:title [title (plot-title)]
#:x-label [x-label (plot-x-label)]
#:y-label [y-label (plot-y-label)]
#:aspect-ratio [aspect-ratio (plot-aspect-ratio)]
#:legend-anchor [legend-anchor (plot-legend-anchor)])
(define fail/kw (make-raise-keyword-error 'plot-frame))
(cond
Expand All @@ -160,6 +166,8 @@
[(and title (not (or (string? title) (pict? title)))) (fail/kw "#f, string or pict" '#:title title)]
[(and x-label (not (or (string? x-label) (pict? x-label)))) (fail/kw "#f, string or pict" '#:x-label x-label)]
[(and y-label (not (or (string? y-label) (pict? y-label)))) (fail/kw "#f, string or pict" '#:y-label y-label)]
[(and aspect-ratio (not (and (rational? aspect-ratio) (positive? aspect-ratio))))
(fail/kw "#f or positive real" '#:aspect-ratio aspect-ratio)]
[(not (legend-anchor/c legend-anchor)) (fail/kw "legend-anchor/c" '#:legend-anchor legend-anchor)])

;; make-snip will be called in a separate thread, make sure the
Expand All @@ -171,7 +179,8 @@
(plot-snip
renderer-tree
#:x-min x-min #:x-max x-max #:y-min y-min #:y-max y-max #:width width #:height height
#:title title #:x-label x-label #:y-label y-label #:legend-anchor legend-anchor)))
#:title title #:x-label x-label #:y-label y-label #:legend-anchor legend-anchor
#:aspect-ratio aspect-ratio)))
(make-snip-frame make-snip width height (if title (format "Plot: ~a" title) "Plot")))

;; ===================================================================================================
Expand All @@ -186,6 +195,7 @@
#:title (U String pict #f)
#:x-label (U String pict #f)
#:y-label (U String pict #f)
#:aspect-ratio (U Nonnegative-Real #f)
#:legend-anchor Legend-Anchor
#:out-file (U Path-String Output-Port #f)
#:out-kind (U 'auto Image-File-Format)
Expand All @@ -201,6 +211,7 @@
#:title [title (plot-title)]
#:x-label [x-label (plot-x-label)]
#:y-label [y-label (plot-y-label)]
#:aspect-ratio [aspect-ratio (plot-aspect-ratio)]
#:legend-anchor [legend-anchor (plot-legend-anchor)]
#:out-file [out-file #f]
#:out-kind [out-kind 'auto]
Expand All @@ -226,6 +237,8 @@
[(and title (not (or (string? title) (pict? title)))) (fail/kw "#f, string or pict" '#:title title)]
[(and x-label (not (or (string? x-label) (pict? x-label)))) (fail/kw "#f, string or pict" '#:x-label x-label)]
[(and y-label (not (or (string? y-label) (pict? y-label)))) (fail/kw "#f, string or pict" '#:y-label y-label)]
[(and aspect-ratio (not (and (rational? aspect-ratio) (positive? aspect-ratio))))
(fail/kw "#f or positive real" '#:aspect-ratio aspect-ratio)]
[(not (legend-anchor/c legend-anchor)) (fail/kw "legend-anchor/c" '#:legend-anchor legend-anchor)]
[(and out-kind (not (plot-file-format/c out-kind))) (fail/kw "plot-file-format/c" '#:out-kind out-kind)]
[(not (plot-file-format/c out-kind)) (fail/kw "plot-file-format/c" '#:out-kind out-kind)]
Expand All @@ -241,18 +254,21 @@
(plot-file
renderer-tree out-file out-kind
#:x-min x-min #:x-max x-max #:y-min y-min #:y-max y-max #:width width #:height height
#:title title #:x-label x-label #:y-label y-label #:legend-anchor legend-anchor))
#:title title #:x-label x-label #:y-label y-label #:legend-anchor legend-anchor
#:aspect-ratio aspect-ratio))

(cond [(plot-new-window?)
(define frame
(plot-frame
renderer-tree
#:x-min x-min #:x-max x-max #:y-min y-min #:y-max y-max #:width width #:height height
#:title title #:x-label x-label #:y-label y-label #:legend-anchor legend-anchor))
#:title title #:x-label x-label #:y-label y-label #:legend-anchor legend-anchor
#:aspect-ratio aspect-ratio))
(send frame show #t)
(void)]
[else
(plot-snip
renderer-tree
#:x-min x-min #:x-max x-max #:y-min y-min #:y-max y-max #:width width #:height height
#:title title #:x-label x-label #:y-label y-label #:legend-anchor legend-anchor)])))
#:title title #:x-label x-label #:y-label y-label #:legend-anchor legend-anchor
#:aspect-ratio aspect-ratio)])))
Loading

0 comments on commit c457141

Please sign in to comment.