Skip to content

Commit

Permalink
Document the plot-metrics interface (#103)
Browse files Browse the repository at this point in the history
Pull request #90 implements the plot-metrics interface, a mechanism that allows the user to determine the location of elements on the plot image itself, so plots can be further decorated, it is based on a request in issue #83. While this functionality has been available for a while now, it was not documented. This PR adds documentation to this interface, so users can discover the functionality and use it.
  • Loading branch information
alex-hhh committed Nov 21, 2021
1 parent 9df19f3 commit 8e0e382
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 26 deletions.
20 changes: 10 additions & 10 deletions plot-doc/plot/scribblings/plotting.scrbl
Expand Up @@ -32,7 +32,7 @@ Each 3D plotting procedure behaves the same way as its corresponding 2D procedur
[#: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]
) (or/c (is-a?/c snip%) void?)]{
) (or/c (and/c (is-a?/c snip%) (is-a?/c plot-metrics<%>)) void?)]{
Plots a 2D renderer or list of renderers (or more generally, a tree of renderers), as returned by @(racket points), @(racket function), @(racket contours), @(racket discrete-histogram), and others.

By default, @(racket plot) produces a Racket value that is displayed as an image and can be manipulated like any other value.
Expand Down Expand Up @@ -85,7 +85,7 @@ The @(racket #:lncolor) keyword argument is also accepted for backward compatibi
[#: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]
) (or/c (is-a?/c snip%) void?)]{
) (or/c (and/c (is-a?/c snip%) (is-a/c plot-metrics<%>)) void?)]{
Plots a 3D renderer or list of renderers (or more generally, a tree of renderers), as returned by @(racket points3d), @(racket parametric3d), @(racket surface3d), @(racket isosurface3d), and others.

When the parameter @(racket plot-new-window?) is @(racket #t), @(racket plot3d) opens a new window to display the plot and returns @(racket (void)).
Expand All @@ -108,9 +108,9 @@ The @(racket #:az) and @(racket #:alt) keyword arguments are backward-compatible
}

@defproc[(plot-snip [<plot-argument> <plot-argument-contract>] ...)
(is-a?/c 2d-plot-snip%)]
(and/c (is-a?/c 2d-plot-snip%) (is-a?/c plot-metrics<%>))]
@defproc[(plot3d-snip [<plot-argument> <plot-argument-contract>] ...)
(is-a?/c snip%)]
(and/c (is-a?/c snip%) (is-a?/c plot-metrics<%>))]
@defproc[(plot-frame [<plot-argument> <plot-argument-contract>] ...)
(is-a?/c frame%)]
@defproc[(plot3d-frame [<plot-argument> <plot-argument-contract>] ...)
Expand Down Expand Up @@ -142,13 +142,13 @@ for more details.
[#:<plot3d-keyword> <plot3d-keyword> <plot3d-keyword-contract>] ...)
void?]
@defproc[(plot-pict [<plot-argument> <plot-argument-contract>] ...)
pict?]
plot-pict?]
@defproc[(plot3d-pict [<plot3d-argument> <plot3d-argument-contract>] ...)
pict?]
plot-pict?]
@defproc[(plot-bitmap [<plot-argument> <plot-argument-contract>] ...)
(is-a?/c bitmap%)]
(and/c (is-a?/c bitmap%) (is-a?/c plot-metrics<%>))]
@defproc[(plot3d-bitmap [<plot3d-argument> <plot3d-argument-contract>] ...)
(is-a?/c bitmap%)]{
(and/c (is-a?/c bitmap%) (is-a?/c plot-metrics<%>))]{
Plot to different non-GUI backends.
These procedures accept the same arguments as @(racket plot) and @(racket plot3d), except deprecated keywords, and @racket[#:out-file] and @racket[#:out-kind].

Expand Down Expand Up @@ -182,15 +182,15 @@ Use @(racket plot-bitmap) or @(racket plot3d-bitmap) to create a @(racket bitmap
[width (>=/c 0)]
[height (>=/c 0)]
[#:<plot-keyword> <plot-keyword> <plot-keyword-contract>] ...)
void?]
(is-a?/c plot-metrics<%>)]
@defproc[(plot3d/dc [renderer-tree (treeof (or/c renderer3d? nonrenderer?))]
[dc (is-a?/c dc<%>)]
[x real?]
[y real?]
[width (>=/c 0)]
[height (>=/c 0)]
[#:<plot3d-keyword> <plot3d-keyword> <plot3d-keyword-contract>] ...)
void?]{
(is-a?/c plot-metrics<%>)]{
Plot to an arbitrary device context, in the rectangle with width @(racket width), height @(racket height), and upper-left corner @(racket x),@(racket y).
These procedures accept the same arguments as @(racket plot) and @(racket plot3d), except deprecated keywords, and @racket[#:out-file] and @racket[#:out-kind].

Expand Down
133 changes: 133 additions & 0 deletions plot-doc/plot/scribblings/utils.scrbl
Expand Up @@ -582,3 +582,136 @@ Convert @racket[plot-time]s to real seconds, and vice-versa.
(plot-time+ (plot-time 32 0 12 1)
(plot-time 32 0 14 1))]
}

@section{Plot Metrics}

@definterface[plot-metrics<%> ()]{

The @racket[plot-metrics<%>] interface allows obtaining plot area positions
on the plots returned by @racket[plot], @racket[plot-snip],
@racket[plot-bitmap], @racket[plot/dc], as well as their 3D variants,
@racket[plot3d], @racket[plot3d-snip], @racket[plot3d-bitmap] and
@racket[plot3d/dc]. All plot objects returned by these functions implement
this interface.

For plots created by @racket[plot-pict] and @racket[plot3d-pict], there is a
separate set of functions that provide the same functionality, for example,
see @racket[plot-pict-bounds].

@defmethod[(get-plot-bounds) (vectorof (vector/c real? real?))]{

Return the bounds of the plot as a vector of minimum and maximum values,
one for each axis in the plot. For 2D plots, this method returns a vector
of two elements, for the X and Y axes, while 3D plots return a vector of
three elements for the X, Y and Z axes.

The values returned are in plot coordinates, to obtain the coordinates on
the drawing surface (i.e. image coordinates), use @method[plot-metrics<%>
plot->dc] on these bounds.

Plot bounds for interactive plots, like those produced by @racket[plot]
and @racket[plot-snip], can change as the user zoom in and out the plot,
@method[plot-metrics<%> get-plot-bounds] always returns the current bounds
of the plot, but they might be invalidated by a user operation.

}

@defmethod[(plot->dc [coordinates (vectorof real?)]) (vectorof real?)]{

Convert @racket[coordinates] from plot coordinate system to the drawing
coordinate system (that is, image coordinates). For 2D plots,
@racket[coordinates] is a vector of two values, the X and Y coordinates on
the plot, while for 3D plots it is a vector of three values, the X, Y and
Z coordinates.

This method can be used, for example, to determine the actual location on
the image where the coordinates @racket[0], @racket[0] are. It can also
be used to determine the location of the plot area inside the image, by
calling it on the plot bounds returned by @method[plot-metrics<%> get-plot-bounds].

For interactive plots, the coordinates might change as the user zooms in
and out the plot.

}

@defmethod[(dc->plot [coordinates (vectorof real?)]) (vectorof real?)]{

For 2D plots, this method returns the 2D plot coordinates that correspond
to the input @racket[coordinates], which are in the draw context
coordinate system.

For 3D plots, this method returns a 3D position on the plane perpendicular
to the user view for the plot. Together with the normal vector for this
plane, returned by @method[plot-metrics<%> plane-vector], the projection
line can be reconstructed.

This is the reverse operation from @method[plot-metrics<%> plot->dc] and
same remark about the user zooming in and out the plot applies.

}

@defmethod[(plane-vector) (vectorof real?)]{

Return the unit vector representing the normal of the screen through the
plot origin. For 2D plots this always returns @racket[#(0 0 1)], for 3D
plots this unit vector can be used to reconstruct plot coordinates from
draw context coordinates.

For interactive 3D plots, the returned value will change if the user
rotates the plot.

}

@history[#:added "8.1"]
}

@defproc[(plot-pict? [any any/c]) boolean?]{

Return @racket[#t] if @racket[any] is a plot returned by @racket[plot-pict].
This can be used to determine if the functions @racket[plot-pict-bounds],
@racket[plot-pict-plot->dc], @racket[plot-pict-dc->plot] and
@racket[plot-pict-plane-vector] can be called on it.

@history[#:added "8.1"]

}

@defproc[(plot-pict-bounds [plot plot-pict?]) (vectorof (vector/c real? real?))]{

Return the bounds of the plot returned by @racket[plot-pict]. See
@method[plot-metrics<%> get-plot-bounds] for more details.

@history[#:added "8.1"]

}

@defproc[(plot-pict-plot->dc [plot plot-pict?] [coordinates (vectorof real?)])
(vectorof real?)]{

Convert the plot @racket[coordinates] to draw context coordinates for the
@racket[plot]. See @method[plot-metrics<%> plot->dc] for more details.

@history[#:added "8.1"]

}

@defproc[(plot-pict-dc->plot [plot plot-pict?] [coordinates (vectorof real?)])
(vectorof real?)]{

Convert the draw contect @racket[coordinates] to plot coordinates for the
@racket[plot]. See @method[plot-metrics<%> dc->plot] for more details.

@history[#:added "8.1"]

}

@defproc[(plot-pict-plane-vector [plot plot-pict?]) (vectorof real?)]{

Return the unit vector representing the normal of the screen through the
plot origin. For 2D plots this always returns @racket[#(0 0 1)], for 3D
plots this can be used to reconstruct plot coordinates from draw context
coordinates. See @method[plot-metrics<%> plane-vector] for more details.

@history[#:added "8.1"]

}
25 changes: 12 additions & 13 deletions plot-lib/plot/private/common/plotmetrics.rkt
Expand Up @@ -3,26 +3,26 @@
;; Untyped interface / contract
(module untyped racket/base
(require racket/class
racket/contract
racket/match
racket/draw)
racket/contract)

(provide plot-metrics<%>
plot-metrics-object/c)
plot-metrics-object/c
interface?)

(define plot-metrics<%> (interface ()
get-plot-bounds
dc->plot
plot->dc
plane-vector
get-plot-metrics-functions))
(define plot-metrics<%>
(interface ()
get-plot-bounds
dc->plot
plot->dc
plane-vector
get-plot-metrics-functions))

(define plot-metrics-object/c
(object/c [get-plot-bounds (->m (vectorof (vector/c real? real?)))]
[plot->dc (->m (vectorof real?) (vectorof real?))]
[dc->plot (->m (vectorof real?) (vectorof real?))]
[plane-vector (->m (vectorof real?))]
[get-plot-metrics-functions (->m (values (-> (vectorof (vector/c real? real?)))
[get-plot-metrics-functions (->m (list/c (-> (vectorof (vector/c real? real?)))
(-> (vectorof real?) (vectorof real?))
(-> (vectorof real?) (vectorof real?))
(-> (vectorof real?))))]))
Expand Down Expand Up @@ -81,7 +81,6 @@

(define plot-metrics% (plot-metrics-mixin object%))


(struct plot-pict pict ([bounds : (Vectorof (Vectorof Real))]
[plot->dc : (-> (Vectorof Real) (Vectorof Real))]
[dc->plot : (-> (Vectorof Real) (Vectorof Real))]
Expand All @@ -94,4 +93,4 @@

(plot-pict (pict-draw P) (pict-width P) (pict-height P) (pict-ascent P)
(pict-descent P) (pict-children P) (pict-panbox P) (pict-last P)
(bounds) ->dc ->plot (plane)))
(bounds) ->dc ->plot (plane)))
2 changes: 2 additions & 0 deletions plot-lib/plot/private/utils-and-no-gui.rkt
Expand Up @@ -21,9 +21,11 @@
Legend-Anchor)

(require "common/plotmetrics.rkt")
(require (only-in (submod "common/plotmetrics.rkt" untyped) plot-metrics<%>))

(provide
Plot-Metrics<%>
plot-metrics<%>
plot-pict?
Plot-Pict
plot-pict-bounds
Expand Down
1 change: 1 addition & 0 deletions plot-lib/plot/utils.rkt
Expand Up @@ -2,6 +2,7 @@

(require "private/utils-and-no-gui.rkt")
(provide (all-from-out "private/utils-and-no-gui.rkt"))
(provide plot-metrics<%>)

(require "private/common/contract.rkt"
"private/common/leftover-contracts.rkt"
Expand Down
10 changes: 7 additions & 3 deletions plot-test/plot/tests/PRs/90.rkt
@@ -1,7 +1,11 @@
#lang racket
(require rackunit
racket/draw pict (only-in racket/gui/base sleep/yield)
plot (submod plot/private/common/plotmetrics untyped))
(require pict
plot
racket/draw
(only-in racket/gui/base
sleep/yield)
rackunit)


; tests for PR#90, https://github.com/racket/plot/pull/90
; "Plotmetrics: access/calculate data about the plot area"
Expand Down

0 comments on commit 8e0e382

Please sign in to comment.