I saw this figure in Leland Wilkinson's book the Grammar of Graphics and was wondering how I could go about creating something similar in R.
I am suspicious this could be done using rgl, persp3d, but there's a couple aspects that are unclear to me like how to create the conformal mapping shown in the coordinates of the XY plane, as well as how to create the 2D color map in a 3D context.
Any advice would be much appreciated. Thanks!
That should be possible with rgl, but there might be some snags in the details. Here's the outline:
The green surface does not appear to have a rectangular base,
so you'll pass matrices for all of x, y and z coordinates to surface3d() to draw it.
I can't tell if the map is on a flat surface with curved edges, or if it's a curved surface. In either case, you plot the surface with a 2D texture showing the map and the contours.
a. To produce that 2D texture, use whatever mapping software you've got, and output the image to a PNG file.
b. To put it on the surface, use surface3d() with arguments texture = <filename>, texture_s = ..., texture_t = ...) where texture_s and texture_t are set to coordinates in the image (bottom left = (0,0), top right = (1,1)) corresponding to each x and y location. The z value is
either constant or varying depending on whether you want it flat
or curved.
The axes will be drawn with axis3d.
Related
I need to produce the star map with constellations etc in the Mollweide projection (elliptical projection giving 360 view angle, used in plotting night sky). I found a recipe at https://kimnewzealand.github.io/2019/02/21/celestial-maps/ with the use of sf package and converting the default EPSG:4326 data of the sky objects into Mollweide projection.
At some stage the data is converted to the Mollweide projection using the command:
constellation_lines_sf_trans<- st_transform(constellation_lines_sf_trans, crs = "+proj=moll")
The resulting image, reproduced along the lines as described in the link, looks like:
It is fine, however, the coordinate system is equatorial, that is basically with the same rotation axis as all coordinate systems on the Earth, like WGS84 (North Pole upwards). For example, the Milky Way is shown on this plot, going at some angle 60 degrees. We need the so called galactic coordinates: this is the coordinate plane coinciding with the plane of our Galaxy. So, Milky way here would be just a horizontal line of the ellipse axis. For example, the solution found elsewhere, seems to use the same technique, but the code is not given there:
Here Milky Way is a horizontal line, and the North Pole is in the upper left corner (denoted as np; for example, here one can see the distorted recognizable constellations of Ursa Major/Minor around the North Pole). I would take this image, but there is a blind spot (showing the blind zone of an observatory which cannot reach this region in the sky), so I would like to reproduce this image: constellations + Mollweide projection + "galactic" orientation of the reference frame.
We are able to convert between variety of coordinate systems in R packages. It seems that most GIS tools use various flavors of Earth-related coordinate systems and projections, based to the rotation of the Earth (North Pole up), for majority of applications, needed for GIS. The question is whether it is possible to load and convert to a predefined galactic coordinate system (or, for example, to the ecliptic system), or to perform this conversion on the fly in the scripts with manual conversion of star data
EDIT: Actually, after further research, it appears that it all comes down to having your projection do a rotation. This also happens in the code on the interactive example I mention farther below. To make it center of the Galactic center, you need to rotate by [93.5949, 28.9362, -58.5988], which specify the [lambda, phi, gamma] rotation angles in degrees about each spherical axis. (when you rotate, there's no need to convert your ra or dec coordinates to galactic coordinates anymore.)
I don't know enough about mapping in R to be able to say if it's possible to specify a rotation on a projection, but here's an amazing example that shows this process with d3.js (and for those truly interested, shows where the angles come from). In case it's not possible, perhaps the route below would still be viable.
I was investigating the same thing, and I might've found something. I think that you first need to convert your equatorial ra (right ascension) and dec (declination) coordinates to galactic coordinates. And then apply a (Mollweide) projection. I'm not sure if that is completely correct since my case was slightly different, but at least this worked for me:
The dataset has rows of ra &dec in equatorial coordinates (given in degrees in my case)
Using the euler function of the astrolibR package, I calculate the Galactic longitude gl and latitude gb (ps: you can also use the glactc function):
data$gl <- euler(data$ra, data$dec, select=1)$ao
data$gb <- euler(data$ra, data$dec, select=1)$bo
Next, using these new coordinates I apply the Aitoff projection that is also part of the astrolibR package to get back x and y coordinates:
data$x <- -aitoff(data$gl, data$gb)$x
data$y <- aitoff(data$gl, data$gb)$y
which I can then plot
ggplot(data, aes(x, y)) + geom_point(shape=16, size = 0.1, alpha = 0.2) + coord_fixed()
(the image below is based on my own dataset of observations, the "darker line" follows the ecliptic line, and the two blobs in the lower right are the Large & Small Magellanic Clouds)
I found it useful to compare against this interactive map and setting the coordinates to "galactic", centering on 0,0 and then trying different kinds of projections.
Perhaps you can try applying the Mollweide projection with the gl and gb coordinates instead?
I am really new in programming with C#. I have an Array of points in the following form
//An Array containing point coordinates:
double[,] graphData=new double[100,3];
//Each element of graph data contain coordinate of a point:
graphData[1;:]=(x1,y1,z1);
I wanna draw a surface using ILNumerics. I couldn't find any example for this case. Would you please help me?
The link posted in the accepted answer points to an outdated part of the ILNumerics documentation which is obsolete now. Up from version 3, surfaces utilize a new scene graph based rendering API.
Documentation: http://ilnumerics.net/surface-plots.html
However, the linke posted by Roy Dictus may help in explaining how to turn your data into matrix shaped data, suitable for surface rendering.
Basically, surfaces create a mesh based on the matrix shaped input data. It connects the incoming points according to their location in the input matrix. So instead of a list of points you have to provide:
a single matrix of Z values, if a regular grid of heights values is to be rendered only, or
same shaped matrices for Z, X and Y values for non-regular grids and parametric surfaces.
How to plot a 3D Surface using ILNumerics: http://ilnumerics.net/forum/index.php?p=/discussion/163/how-to-plot-a-3d-surface-/p1
I have a bunch of points in a rectangular x/y space which I would like to project onto a sphere. As in, I am trying to write this function:
function point_on_sphere(2dx:Number, 2dy:Number) : Vector3D
{
//magic
return new Vector3D(3dx, 3dy, 3dz);
}
I have been trying to first plot the points on to a cylinder and then map those points to a sphere as directed by this wikipedia page. However, those formulas assume a constant z=0, which doesn't really do what I want.
I'm using actionscript 3 / flex, but any pseudo code or pushes in the right direction would be greatly appreciated.
Just to clarify: I'm not trying to apply a texture to a sphere object, but rather to place objects along an imaginary sphere.
There is no one right answer. You can choose different approaches based on how you want to place the objects along the sphere.
Is it OK for the objects to get nearer and nearer to each other as you get closer to the sphere's "poles"? Why wouldn't the normal texture-mapping projection actually work for you?
I have a plot like this:
http://i.imgur.com/i9xp5.png
I need the data coordinates of points in order to plot wind barbs.
Now, if I wanted a wind barb to be drawn at x=100, y=20, is there a way I can obtain the data coordinates of that ( or other ) points of my plot?
Would the ARROW procedure be of any use to you? It looks like you could
just pass it your data coordinates (x0=100, y0=20) for the base of the arrow,
and another set of coordinates x1 and y1 representing the length and direction for the arrowhead end. It should take care of placing and scaling them properly on your plot.
But I don't think ARROW gives you any control over the arrow style, except for color,
heaviness of the lines, and filled vs. unfilled. If you need to use a different
shape, I think you might have to express it as an array of XY points to define
the vertices of your custom arrow symbol, then rotate, scale, translate, and PLOTS
line segments between each symbol vertex.
The DATA and DEVICE graphics keywords tell the various plotting routines whether
the coordinates are in data coordinates or device coordinates. I'm not sure from
your description which is the appropriate setting, but one of them should do what you want.
Given a list of points that form a simple 2d polygon oriented in 3d space and a normal for that polygon, what is a good way to determine which points are specific 'corner' points?
For example, which point is at the lower left, or the lower right, or the top most point? The polygon may be oriented in any 3d orientation, so I'm pretty sure I need to do something with the normal, but I'm having trouble getting the math right.
Thanks!
You would need more information in order to make that decision. A set of (co-planar) points and a normal is not enough to give you a concept of "lower left" or "top right" or any such relative identification.
Viewing the polygon from the direction of the normal (so that it appears as a simple 2D shape) is a good start, but that shape could be rotated to any arbitrary angle.
Is there some other information in the 3D world that you can use to obtain a coordinate-system reference?
What are you trying to accomplish by knowing the extreme corners of the shape?
Are you looking for a bounding box?
I'm not sure the normal has anything to do with what you are asking.
To get a Bounding box, keep 4 variables: MinX, MaxX, MinY, MaxY
Then loop through all of your points, checking the X values against MaxX and MinX, and your Y values against MaxY and MinY, updating them as needed.
When looping is complete, your box is defined as MinX,MinY as the upper left, MinX, MaxY as upper right, and so on...
Response to your comment:
If you want your box after a projection, what you need is to get the "transformed" points. Then apply bounding box loop as stated above.
Transformed usually implies 2D screen coordinates after a projection(scene render) but it could also mean the 2D points on any plane that you projected on to.
A possible algorithm would be
Find the normal, which you can do by using the cross product of vectors connecting two pairs of different corners
Create a transformation matrix to rotate the polygon so that it is planer in XY space (i.e. normal alligned along the Z axis)
Calculate the coordinates of the bounding box or whatever other definition of corners you are using (as the polygon is now aligned in 2D space this is a considerably simpler problem)
Apply the inverse of the transformation matrix used in step 2 to transform these coordinates back to 3D space.
I believe that your question requires some additional information - namely the coordinate system with respect to which any point could be considered "topmost", or "leftmost".
Don't forget that whilst the normal tells you which way the polygon is facing, it doesn't on its own tell you which way is "up". It's possible to rotate (or "roll") around the normal vector and still be facing in the same direction.
This is why most 3D rendering systems have a camera which contains not only a "view" vector, but also "up" and "right" vectors. Changes to the latter two achieve the effect of the camera "rolling" around the view vector.
Project it onto a plane and get the bounding box.
I have a silly idea, but at the risk of gaining a negative a point, I'll give it a try:
Get the minimum/maximum value from
each three-dimensional axis of each
point on your 2d polygon. A single pass with a loop/iterator over the list of values for every point will suffice, simply replacing the minimum and maximum values as you go. The end result is a list that has the "lowest" X, Y, Z coordinates and "highest" X, Y, Z coordinates.
Iterate through this list of min/max
values to create each point
("corner") of a "bounding box"
around the object. The result
should be a box that always contains
the object regardless of axis
examined or orientation (no point on
the polygon will ever exceed the
maximum or minimums you collect).
Then get the distance of each "2d
polygon" point to each corner
location on the "bounding box"; the
shorter the distance between points,
the "closer" it is to that "corner".
Far from optimal, certainly crummy, but certainly quick. You could probably post-capture this during the object's rotation, by simply looking for the min/max of each rotated x/y/z value, and retaining a list of those values ahead of time.
If you can assume that there is some constraints regarding the shapes, then you might be able to get away with knowing less information. For example, if your shape was the composition of a small square with a long thin triangle on one side (i.e. a simple symmetrical geometry), then you could compare the distance from each list point to the "center of mass." The largest distance would identify the tip of the cone, the second largest would be the two points farthest from the tip of the cone, etc... If there was some order to the list, like points are entered in counter clockwise order (about the normal), you could identify all the points. This sounds like a bit of computation, so it might be reasonable to try to include some extra info with your shapes, like the "center of mass" and a reference point that is located "up" above the COM (but not along the normal). This will give you an "up" vector that you can cross with the normal to define some body coordinates, for example. Also, the normal can be defined by an ordering of the point list. If you can't assume anything about the shapes (or even if the shapes were symmetrical, for example), then you will need more data. It depends on your constraints.
If you know that the polygon in 3D is "flat" you can use the normal to transform all 3D-points of the vertices to a 2D-representation (of the points with respect to the plan in which the polygon is located) - but this still leaves you with defining the origin of this coordinate-system (but this don't really matter for your problem) and with the orientation of at least one of the axes (if you want orthogonal axes you can still rotate them around your choosen origin) - and this is where the trouble starts.
I would recommend using the Y-axis of your 3D-coordinate system, project this on your plane and use the resulting direction as "up" - but then you are in trouble in case your plan is orthogonal to the Y-axis (now you might want to use the projected Z-Axis as "up").
The math is rather simple (you can use the inner product (a.k.a. scalar product) for projection to your plane and some matrix stuff to convert to the 2D-coordinate system - you can get all of it by googling for raytracer algorithms for polygons.