-
-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set plot area #7
Comments
Seconded. I have a problem with the x axis, so I "solved" it using the alignment to hide the difference. Perhaps I'd prefer to be able to set the four margins between the plot area and the image area. |
is this still an issue? Please consider adding the label Issues labeled |
Is this a good first issue? I didn't look too much under the hood, but my guess is that there are too many moving parts that interact to place all the parts of the image. (IIRC this is still a problem, and I still think it will be a very useful addition.) |
@gus-massa it was part of a list of 'good first bugs' at https://github.com/racket/racket/wiki/Racketeer-Office-Hours-2017-Task-Ideas |
The margins for the plot area are calculated here
but this is an iterative process looking at the size of the decorations (labels, ticks, etc) and making sure they have enough space to be drawn along the plot area. If we just override these values with user provided values, the user will now have to fiddle with these values, and the labels can enter the plot area or be clipped if the supplied margins are wrong. The alternative would be to separate this calculation and have
Currently, each plot invocation is completely separate and even the plot parameters are captured in structures and used inside a plot call. To implement this functionality we would need to think about how to create a shared plot state across several plots. This would be a useful feature indeed, but it would require a significant redesign of the internals of the plot library. However, if someone has other ideas, I would be happy to help out with the implementation. |
Being able to get a set of plots that all have the same size plot area (and, indeed, even to have the decorations drawn outside the bounding box in "pict" mode) would really be great for using plots in figures in papers! It would make layout so much easier/nicer. |
OK, lets look at the other end of this problem. How should the interface look like? The current situationCurrently each plot call produces a single plot, and "packaging" plots is done outside of the plot library. In the example for this issue, two separate picts were produced using There is a lot of flexibility when it comes to stitching plots together, but all this is outside of the plot library, keeping the How would this work for aligning the areasIf we are to align the plot areas, each plot invocation needs to know about the other plots. These are the current entry points into creating plots:
I can see two broad approaches to this: sub-plots and plot grouping. Sub-plotsPythons This shows the things that mathplotlib can do: Implementing this means we need to add layout functionality to plot, but also means that we can implement things like sharing axes (see mathplotlib examples) Plot GroupsAnother option is to simply "group" plots together somehow. This would work as follows: All plot functions, except for
With plot groups the steps would be:
Implementing this would be simpler (although I am not sure how the API would look), but it would not allow things like sharing axes. |
From very far, the Python approach strikes me as imperative (you get an area to play) while the Plot Group one feels compositional. I have often used an approach like this to figure out the size of picts before I compose them (you create preliminary versions of all the pieces, measure, and then the |
Den fre. 26. jun. 2020 kl. 04.49 skrev Alex Harsányi <
[email protected]>:
OK, lets look at the other end of this problem. How should the interface
look like?
How would this work for aligning the areas
If we are to align the plot areas, each plot invocation needs to know
about the other plots.
An additional, related issue:
Plot returns a pict without further information.
If I want to place additional points, labels, arrows etc using MetaPict
or latex-pict
there is no way of knowing, how pict coordinates maps to the logical
coordinates
that `plot` used to place the plotted objects. Due margins, legends and
axes there is no way
of figuring out how the logical coordinate system is places on the pict.
A way of getting the placement of the logical coordinate system relative
to the pict,
would be a great feature.
/Jens Axel
|
Looking at the python pictures, it seems to me that if I could build a plot by specifying a width and height for the core plot area (and then the decorations sized themselves to that) then I could use the pict library and the existing control of plots to get all those pictures. For example, if I wanted a 2x2 group of plots that shared axies everywhere, I would pict a fixed width and height and then I'd make a plot for the upper-left corner with no axies and a legend, a plot for the lower left with both axes and no legend, and plots for the other two corners with one axis each and then I could use That said, the plot snips do more than just draw, they allow interaction, so I'm not sure of the best way of working that in. Perhaps it is fine to not be able to combine these two pieces of functionality, however. That is, if I want created a plot to be able to interact with it, maybe I'm okay not being able to lay it out super carefully? Or maybe we should really be looking at bulking up things at the |
(And I realize I might not have been completely clear -- the resulting picts would need to have their bounding boxes be set to the plot area only -- so some of the decorations would draw outside the bounding boxes, so the bounding boxes could be used for alignment.) |
In my case, I wanted a few plots of very similar functions. Something like: Text And I really wanted that all the plots use the exact same scale. But I didn't want all of them to be in a single block, because I wanted to put some text between them. I can imagine that in a similar situation I'd like to have the exact same horizontal scale, but I would not care about the vertical scale. |
@soegaard , the plot library uses three coordinate systems, and using the terminology that plot uses, they are:
As such, for a general case, it is not sufficient for the plot to just return a bounding box (or two of them), but it would need to give you access to the drawing area object which provides functions for converting between the three coordinate systems. I am not sure how metapict works, but it is a lot easier to do things the opposite direction: plot already has a Than, there is this statement (emphasis is mine):
The plot library can produce picts, bitmap files, draw onto device context and provide interactive snips. There is also the 3D variant. Any new functionality should be available for all these interfaces. In a different message @rfindler mentioned that:
I disagree: I use interactive plots, and I would like to be able to align them, this is why I participate in this discussion :-). Here is an example where all plots are interactive and also stretch transforms are used to "zoom in" into a section of the plot, all highlighted sections should be aligned: |
Den lør. 27. jun. 2020 kl. 01.07 skrev Alex Harsányi <
[email protected]>:
@soegaard <https://github.com/soegaard> , the plot library uses three
coordinate systems, and using the terminology that plot uses, they are:
- The first one is the *plot coordinates* system, these are the
coordinates of the functions being plotted. For example, if you plot the
sine function from -5 to 5, the plot bounding box will be (-5, 5, -1, 1)
- The last one is the *device context coordinates* system, which uses
the coordinates on the drawing surface. For example, if you want a picture
of 500x500 pixels, the device context coordinates might be (0, 400, 0,
400), to account for the plot decorations
- In the middle sits the *view coordinate* and it is the tricky one.
It is the one which adjusts the plot coordinates according to various axis
transforms. for example, if an axis uses a logarithmic transform, it will
be applied to a plot coordinate before calculating its device context
coordinates. The *view coordinate* system is not defined completely by
its bounding box. This is because plot supports axis transforms for a
subset of the axis (see stretch-transform and collapse-transform)
As such, for a general case, it is not sufficient for the plot to just
return a bounding box (or two of them), but it would need to give you
access to the drawing area object which provides functions for converting
between the three coordinate systems.
I am not sure how metapict works, but it is a lot easier to do things the
opposite direction: plot already has a point-pict function which allows
placing a pict on the plot area, and we could extent the #:label argument
for renderers to accept a pict as well, to handle complex legend rendering,
as I suggested in #58 <#58>
Thanks for clarifying.
Overview:
The overall goal (for me) is to make decorations/annotations without
using plot.
The decoration is rendered as a pict, and then superimposed on the pict
returned from plot.
To make things (hopefully) clearer, let me give an example without metapict
and let's
assume the mapping from view coordinates to device coordinates is affine.
Let's say I have a plot `p` returned from `plot` as a pict.
Now I want to draw on top of that pict (i.e. decorate it) with the standard
tools.
In particular I want to draw a shape that starts in one point and ends in
another.
The way I want to do this is:
1. make a new pict `d` with a certain size
2. draw the shape
3. use a variant of super-impose to place d on top of p.
Thinking aloud, the details are:
ad 1)
The sizes of p and d do not need to be the same, but the scaling from
plot coordinates
into device coordinates need to be the same.
Useful information:
xmin, xmax, ymin, ymax in device coordinates of the plotting area
used by plot
xmin, xmax, ymin, ymax in plot coordinates
Given these I can determine how large the decoration pict d needs to be
and get the scaling right.
ad 2)
I can use the information from 1) to set up a dc transformation that
maps plot coordinates
into device coordinates of d. Then the shape can be drawn.
ad 3)
Aligning both start and end point of the shape needs a mapping from
plot coordinates to device coordinates of p. The information from 1) is
enough.
Note: The existing `point-pict` is not enough; it can only align one of
the points.
In summary: A way to get the plot window in both device and plot
coordinates is enough
for external tools to draw on top of plots produced with `plot`.
One way to extend plot in a compatible way would be to add a keyword
signaling
that the windows are needed and then let plot return some extra values.
If non-linear axes are used, then the view transformation becomes important.
I need to think some more about handling that. Maybe returning functions
mapping to and from view coordinates is enough?
/Jens Axel
|
While working on faceting for Graphite, I came across this work-around for setting the plot area: #lang racket
(require plot/pict pict)
(define (plot-extras-size plotpict)
(match-define (vector (vector x-min x-max)
(vector y-min y-max))
(plot-pict-bounds plotpict))
(match-define (vector x-left y-bottom)
((plot-pict-plot->dc plotpict) (vector x-min y-min)))
(match-define (vector x-right y-top)
((plot-pict-plot->dc plotpict) (vector x-max y-max)))
(define inner-width (- x-right x-left))
(define inner-height (- y-bottom y-top))
(values (- (pict-width plotpict) inner-width)
(- (pict-height plotpict) inner-height)))
(define (plot-with-area plot-thunk area-width area-height)
(match-define-values ((app inexact->exact y-extras)
(app inexact->exact x-extras))
(plot-extras-size (plot-thunk)))
(parameterize ([plot-width (+ area-width y-extras)]
[plot-height (+ area-height x-extras)])
(plot-thunk)))
(plot-with-area (thunk (plot (function sin -2 2)))
1024 768) which works by calculating the size of the non-plot area (as it's presumably invariant and not dependent on Unfortunately, this results in rendering the plot twice, which is probably inefficient. However, it's still likely useful to someone. This can likely be adapted to interactive plots -- but I haven't used them. |
It's hard to align plots with different-sized axis labels. See below -- these are equal-sized figures
vl-append
-ed together (code is far below)Suggestions
Code
The text was updated successfully, but these errors were encountered: