Scaling x vs y axes in 2d plots using plot package (aka aspect ratio ?)

hi, I'm trying out the powerful plotting functions described in
1 Introduction

I have a question starting at the first example:

  (plot (function sin (- pi) pi #:label "y = sin(x)"))

By default evidently, the plotting surface is square. The x-axis values range from -pi to pi as we specify. The y-axis values are computed to range from -1 to 1. By default the plot gets stretched in the y direction (by pi, I surmise) to make the plot fit nicely in the square.

I'm trying to figure out how to have the x and y axes scale the same. I suspected this might work:

  (parameterize ([plot-aspect-ratio 1])
    (plot (function sin (- pi) pi #:label "y = sin(x)")))

But this yields the same result as before.

On a hunch I tried

  [plot-aspect-ratio pi]

The result is closer to what I want, but also not correct.

I'd appreciate any pointers.

Try this:

#lang racket
(require plot)

(define h 300)
(define w (inexact->exact (* 3.14 h)))
(define x-min (* -1.5 pi))
(define x-max (*  1.5 pi))
(define ratio (/ w h))

(plot (function sin (- pi) pi #:label "y = sin(x)")
      #:aspect-ratio ratio
      #:height h #:width w
      #:x-min x-min #:x-max x-max
      #:y-min (/ x-min ratio) #:y-max (/ x-max ratio))

I must admit that I also find aspect-ratio confusing.

1 Like

There are some problems with the above statement:

  • "plotting surface" is not a term used by the plot package, and, as you'll see below, it can mean different things.
  • "by default" only the plot image itself is "square", that is, plot-width is the same as plot height. Anything else that looks square on the plot is just a coincidence.

Different people have different ideas when they talk about the "aspect ratio" of a plot and I'll show some examples below. To make them easier to follow, I will only talk about an aspect ratio of 1:1, that is a "Square". Also, I colored the different regions with different colors to make them easier to follow:

  • the plot image (or simply "the plot") is the blue region
  • the plot area (where the plot data is drawn), is the yellow region
  • finally, there is a red "square" drawn on the plot, this is 1 unit by 1 unit, in plot coordinates, this will make it easier to see the aspect ratio of the "plot domain".

Square plot image

You can create a square plot by specifying the same width and height for the plot (you can of course create any aspect ratio you want by changing these parameters. Note that I placed the legend outside the plot to illustrate that neither the plot area or the plot domain is "square", by default, the plot package will fill the entire available image as best as it can:

(parameterize ([plot-background "lightblue"])
  (plot
   (list
    (rectangles (list (vector (ivl -inf.0 +inf.0) (ivl -inf.0 +inf.0)))
                #:color "lightyellow")
    (rectangles (list (vector (ivl -0.5 0.5) (ivl -0.5 0.5)))
                #:color "lightpink")
    (function sin (- pi) pi #:label "y = sin(x)"))
   #:legend-anchor 'outside-left
   #:width 400 #:height 400
   ))

plot-square-image

Square plot area

You can control the aspect ratio of the plot area using the #:aspect-ratio parameter. In the case below, the area is square, but the plot image is not, and neither is the plot domain:

(parameterize ([plot-background "lightblue"])
  (plot
   (list
    (rectangles (list (vector (ivl -inf.0 +inf.0) (ivl -inf.0 +inf.0)))
                #:color "lightyellow")
    (rectangles (list (vector (ivl -0.5 0.5) (ivl -0.5 0.5)))
                #:color "lightpink")
    (function sin (- pi) pi #:label "y = sin(x)"))
   #:aspect-ratio 1/1
   #:width 800 #:height 400
   ))

Square plot domain

Finally, you can control the aspect ratio of the plot domain by specifying an aspect ratio that takes the X and Y axis ranges into account. Note that this only works for simple cases. The plot package allows logarithmic transforms of the x and y axes, as well as any other transforms, including transformations of only a subset of an axis. It is unclear (at least to me) to specify the "aspect ratio" for such a plot domain.

(parameterize ([plot-background "lightblue"])
  (plot
   (list
    (rectangles (list (vector (ivl -inf.0 +inf.0) (ivl -inf.0 +inf.0)))
                #:color "lightyellow")
    (rectangles (list (vector (ivl -0.5 0.5) (ivl -0.5 0.5)))
                #:color "lightpink")
    (function sin (- pi) pi #:label "y = sin(x)"))
   #:aspect-ratio
   (let ([y-range (- -1 1)]
         [x-range (- (- pi) pi)])
     (/ x-range y-range))
   #:width 800 #:height 400
   ))


Hope this clarifies things somewhat,
Alex.

3 Likes

Thanks, Soegaard for sharing some code.

Thanks, Alex, for your detailed explanations, definitions and demonstration code! That should solve all my misunderstandings and help me get what I wanted.

Cheers, Tim