racket / plot

Other
39 stars 38 forks source link

Add support for specifying the aspect ratio of the plot area #88

Closed alex-hhh closed 3 years ago

alex-hhh commented 3 years ago

Plot will calculate the plot area such that it fills up the entire available size of the plot, but this creates a problem for plots which need to maintain their "shape". For example, by default when plotting a circle, you get an ellipse:

(require plot)
(plot-background "lightblue")
(plot-x-label #f)
(plot-y-label #f)

(plot (polar (lambda (t) 1)) #:width 400 #:height 200)

circle-non-ar

This pull request introduces the #:aspect-ratio parameter for all plot functions and a corresponding plot-aspect-ratio parameter, which allows specifying the ratio between the width and height of the plot area. For example, by specifying an aspect ratio of 1, the plot will actually look like a circle.

(plot (polar (lambda (t) 1)) #:width 400 #:height 200 #:aspect-ratio 1/1)

circle-with-ar

The aspect ratio setting also works for 3D plots.

bdeket commented 3 years ago

Hi, I didn't manage to test it yet and will do so tonight, but if I understand correctly the aspect ratio is defined in terms of the plot-area width and height. I would like to suggest to instead define this in terms of the x and y (and z) axis so that when you are drawing an ellipse you don't need to calculate the right aspect ratio every time you change the shape. An alternative is to add an option axis-constrained? ( I think maple did this ) so you have only two options: maximize the available area or keep axiss with same unit step size

alex-hhh commented 3 years ago

Hi @bdeket , thanks for the feedback. Yes the aspect ratio is defined in terms of the plot area, this seemed more natural to me, especially when using aspect ratios of 4:3 and 16:10. It is also simpler to think about this for 3d plots, where the aspect ratio applies to the view.

Just to make sure I understand what you are suggesting, since I am not familiar with maple. Are you suggesting that the aspect ratio would be defined in terms of plot units, such that, for example, with an aspect ratio of 1, this plot would remain a circle, even though the x-axis range is 4 but the y axis range is 2?

(plot (polar (lambda (t) 1)) #:x-min -2 #:x-max 2 #:y-min -1 #:y-max 1)
bdeket commented 3 years ago

Indeed, that was the idea. I suggested this because the only use case I could think of to use the aspect-ratio is exactly that: keeping plot units in x and y (z) direction exactly in step. But maybe you have another use case, and this question is orthogonal to that.

I think in maple this same ratio for the plot units was also enforced when you started zooming in and out, but I'm not sure anymore (I would consider it a plus)

samth commented 3 years ago

A different approach here might be to allow controlling two kinds of widths/heights separately -- the plot itself and the entire surface. That would allow achieving your result by specifying the plotted area to have size 200x200. This incidentally might be useful for creating plots that are aligned when combined as picts.

rfindler commented 3 years ago

Just to chime in with @samth 's comments, one of the things I have struggled with when using plot (mostly everythign with plot is amazingly smooth sailing!) is when I have multiple plots that I want to put into the same figure and I want the mapping of plot coordinates -> drawn coordinates to be the same for all the plots and I want to put a bunch of plots together into a figure (by doing stuff like hbl-append with the picts that come out of the plot library). Things like the axis labels being different sizes foils me, however. If these changes help with that usecase, that'd be fantastic. Also, a related request might be a few examples that explain how to make this usecase work well in the docs would also be very welcome so people who are using plot for papers find it and know what to do.

bdeket commented 3 years ago

wrt "maintaining shape" I think I still don't completely understand the intent. Is this to address the comment of #85 or to address #7 , or something else entirely?

(plot3d (polar3d (λ (ϕ θ) 1)) #:width 400 #:height 200 #:altitude 0)

b1

(plot3d (polar3d (λ (ϕ θ) 1)) #:width 400 #:height 200  #:altitude 0 #:aspect-ratio 1/1)

b2

If the aspect ratio was in terms of plot-units, the second picture would show a ball(/circle) whatever the view angle


Also, when I start zooming in on your second circle (aspect ratio 1/1) it looks like something goes wrong with calculating the optimum size (too much white space at bottom and left): zoomed

alex-hhh commented 3 years ago

I understand that many of people want #7 and #84 to be implemented and that many people would like to be able to align the plot areas of several plots, for the purpose of writing publications. This pull request does not address any of those issues. Those issues are constantly on my mind, but as of today, I don't know how to implement them in a way that it does not create more problems than it solves. The main problem with them is that the plot package has many use cases, and so far, all proposed solutions handle one or two use cases well, while creating potential problems for other use cases.


The purpose of this feature is to address the question in #85, as well as the problem I had when I wrote my Plot Animations blog post, where I had to manually adjust the size of the plot, until the circle looked like a circle. As @bdeket noted, #85 is not addressed perfectly...

To a certain extent can also be used as an example of how many files have to change to add one single parameter to the plot API, which I think is one drawback of the current plot API...

The problem is addressed in such a way that, I feel it is easy for someone with a programming background to use the feature and it works reasonably well with all use cases of the plot package. In particular:

@bdeket , I will look into the issue you noticed with the "deep zooming"

rfindler commented 3 years ago

Indeed. My bad @alex-hhh . Sorry.

alex-hhh commented 3 years ago

Hi @bdeket , this is the result of zooming in excessively with the current plot package (without the changes in this PR). It looks like something is wrong with calculating the plot area size, but it is not introduced by this PR.

(require plot)
(plot-background "lightblue")
(plot-x-label #f)
(plot-y-label #f)

(plot (polar (lambda (t) 1)) #:width 400 #:height 200)

image

alex-hhh commented 3 years ago

With regards to the 3D plots being distorted, this is caused by the fact that the projection itself is not considering the aspect ratio, I had a brief look at the code in plot-area.rkt for the 3D plots and it looks like the code is doing "manual" calculations instead of defining "world->view", "view->projection" and "projection->screen" matrices, so it is not easy to change to take the aspect ratio into account -- it would be a nice improvement to rewrite this aspect of the 3D plots. This would also make 3D plots faster, since going from 3D world coordinates to DC coordinates would be a single matrix multiplication instead of a chain of transformations, as it is now.

This refactoring would also have to be done if we implement the "plot units" based aspect ratio.