There are many ways to create a 3D Earth that is rotatable (see here, here, related here), but most of them have some drawbacks. These issues mainly stem from either CountryData
or the fact that 3D shapes are not easy to handle. How can one efficiently overcome these problems? How to create a 3D rotateable, high-resolution-textured or polyon-based, fast-response, good-looking Earth?
Update:
Specific problem to solve: Given a 3D Earth, how can a 2D plot be layered on the surface such that only those parts of the plot appear that are above continents?
In other words: How to plot a species' distribution over the globe? My present method is quite tedious and is really slow. It involves the creation of a continent-texture map, the rasterization of some random distribution patches (any will suffice, mine is taken from here), some image-processing algorithm to color the intersection of continents and the distribution (as Mathematica lacks proper polygon-intersection tools at the moment), and projecting the result over the sphere. This has various problems apart from slowness (see below the example). Following is a test-creature that was obliterated from the Italian Peninsula.
Here I list the methods known to me to create the globe, and their shortcomings:
1. Make a 3D wireframe from polygon data
Extract 2D polygon data for each country & continent from CountryData
, convert them to 3D and project coordinates to a sphere. Issues:
- looks ugly if only
"SchematicPolygon"
-s are used (too few points) - too much computation if
"FullPolygon"
-s are used (too many points) - edge transparency slows down interactive manipulation terribly, though for aesthetics, it is needed sometimes
- no perfect way to put a sphere under the wireframe to prevent see-through, or to put e.g. a vegetation map texture to go with the vector-country-borders (see next)
- no easy way to make countries filled polygons, as it either creates artefacts (fill goes out of boundary, unclosed polygons, etc.) or interferes with sphere surface (if present under the wireframe), as polygons are not bent according to the curvature of the globe.
Example:
mapData = CountryData[#, "SchematicPolygon"] & /@
Flatten[CountryData /@ CountryData["Continents"]];
SC[{lat_, lon_}] := {Cos[lon \[Degree]] Cos[lat \[Degree]],
Sin[lon \[Degree]] Cos[lat \[Degree]], Sin[lat \[Degree]]};
mapDataSphere =
Flatten@(mapData /. n : {_Real, _Real} :> SC@Reverse@n);
Graphics3D[{Hue[.58, .1, 1], FaceForm@White,
EdgeForm@{[email protected], [email protected]}, mapDataSphere},
ImageSize -> 300, Boxed -> False]
2. Make a texture bitmap and project it onto a sphere
Create a high-resolution 2D map of the world, and apply it to e.g. SphericalPlot3D
. It produces a globe that can be rotated quite easily, though it has other issues:
- By using textures, one looses all the advantages of vector graphics. For example any change to the surface map involves image processing (i.e. layering a species' distribution over the continents), which is usually slow, especially for textures of high resolution.
- The resolution of the texture map does not seem to be used for its full extent, as the applied texture looks less crisp than the original 2D map.
SphericalPlot3D
produces artefacts (holes in the surface, weird shadow at boundary)- If the texture map is not rasterized before, it produces artefacts (see lines across North America)
Examples:
mapData =
CountryData[#, "FullPolygon"] & /@
Flatten[CountryData /@ CountryData["Continents"]];
map = Graphics[{White, EdgeForm@{Gray, AbsoluteThickness@0}, mapData},
ImageSize -> 2000, PlotRangePadding -> 0,
PlotRange -> {{-180, 180}, {-90, 90}},
Background -> Hue[.58, .1, 1]];
SphericalPlot3D[1, {u, 0, Pi}, {v, 0, 2 Pi},
TextureCoordinateFunction -> ({#5 + .5, 1 - #4} &),
PlotStyle -> Texture@map, SphericalRegion -> True, Axes -> False,
Boxed -> False, Lighting -> "Neutral", Mesh -> False,
PlotRangePadding -> 0, RotationAction -> "Clip", ImageSize -> 300]
Various artefacts in Mark's answer, when zoomed on to the South Pole:
Note polygon spiral-lines (polygon issue, can be cured by rasterization); low resolution (can be increased, but not to a level when zooming on like this does not reveal pixels); the alignment issue at the surface boundary (thin blue line pointing to the pole) due to 3D plotting; and the blue point right at the pole (projection issue).
3. Simulate 3D with high-resolution bitmap in 2D
This is a hypothetic way I haven't tried. First, create a large bitmap of the world. Tile the space periodically with it, and use an orthographic projection to simulate a 3D sphere-like lens effect whenever the map is dragged by the mouse. By this way 3D can be simulated in 2D. Could be faster than the texture mapped sphere.
Texture map issues
Why is it that many geographic features are not shown consistently by CountryData
? I would assume this returns a full world map, but I guess since Antarctica is not a sovereign country, it is omitted:
Graphics[CountryData[#, "SchematicPolygon"] & /@ CountryData[All], ImageSize -> 400]
But I cannot explain the missing features of the second plot below (e.g. Alaska). How come that the "Polygon"
specification, that is supposed to be more detailed than "SchematicPolygon"
, is actually missing features the other has?
{
Graphics[CountryData[#, "SchematicPolygon"] & /@ CountryData["Continents"], ImageSize -> 400],
Graphics[CountryData[#, "Polygon"] & /@ CountryData["Continents"], ImageSize -> 400]
}
Texture[Rasterize[pic, ImageSize -> 1500]]
instead ofShow
in Mark's code. $\endgroup$CountryData
" to 2) "How to make a 3D globe" to now 3) "Plot geographic data over a 3D globe" over the course of a month! I think this is excessive— questions should be updated with info, not changed in scope! It makes Fx's and FJRA's answers look completely out of place. It's also on the verge of being bumped to CW, for those who care. I think that this should've been 3 separate questions or one well thought out question. It's too late to do anything now $\endgroup$