36  Globe

What does the data look like on the earth itself? The map chapter flattened the sphere to fit a page. This chapter keeps the sphere round, and turns it toward you.

quakes_fiji holds a thousand earthquakes recorded near Fiji, one row for each. Here is the map chapter’s first sentence, which draws them, and beside it the same sentence with globe() in place of map(), turned to face Fiji:

quakes_fiji: first 5 of 1000 rows
east north elevation magnitude slab
181.62 -20.42 -562 4.8 540-630 km
181.03 -20.62 -650 4.2 630-720 km
184.10 -26.00 -42 5.4 0-90 km
181.66 -17.97 -626 4.1 540-630 km
181.96 -20.42 -649 4.0 630-720 km
(data(quakes_fiji) + point + x(east) + y(north) + map() +
   title("map()")) |
  (data(quakes_fiji) + point + x(east) + y(north) +
     globe(turn = 178, tilt = -18) + title("globe(turn = 178, tilt = -18)"))
((data(quakes_fiji) + point + x(col.east) + y(col.north) + map() +
   title("map()")) |
  (data(quakes_fiji) + point + x(col.east) + y(col.north) +
     globe(turn = 178, tilt = -18) + title("globe(turn = 178, tilt = -18)")))
(data(quakes_fiji) + point + x(:east) + y(:north) + map() +
  title("map()")) |
  (data(quakes_fiji) + point + x(:east) + y(:north) +
  globe(turn = 178, tilt = -18) + title("globe(turn = 178, tilt = -18)"))
beside(plot(data(quakes_fiji), point, x(col.east), y(col.north), map(),
  title("map()")),
  plot(data(quakes_fiji), point, x(col.east), y(col.north),
  globe({ turn: 178, tilt: -18 }),
  title("globe(turn = 178, tilt = -18)")))
180° -30° -20° map() North East globe(turn = 178, tilt = -18)

“Given quakes Fiji: points, x is east, y is north, in the map space, beside the same on the globe.”

x is longitude and y is latitude, exactly as on the map. What changed is how the two numbers become a position on the page. Each point is now drawn at its place on the sphere. A sphere seen from one side is a disk, and that disk is what the plot draws.

36.1 The view

A globe shows one half of the earth, so the choice of half matters. turn and tilt name the place the view faces, and they are the same two arguments space() takes. turn is the longitude at the center of the disk, and tilt is the latitude. The chapter’s first plot faces Fiji. Leave both out and the view faces longitude zero and latitude zero, where the equator crosses the prime meridian.

turn is a longitude, so 190 and -170 name the same view: 190 degrees east is 170 degrees west. tilt is a latitude, so it runs from -90 to 90 and no further.

In the web edition the angle you write is only the view the globe opens at. Drag it and it turns, the way the cube in Space turns, and the far half of the earth comes into view. The reset button returns to the view the sentence asked for. In the PDF a plot keeps its one view, which is why this chapter also draws some data at a second angle.

36.2 What a view hides

Half the earth faces away, and data on that half is hidden behind the sphere. gog counts what a view hides rather than dropping it in silence. The next plot draws the earthquakes over world_borders, the map chapter’s table of the points that trace every country’s outline:

world_borders: first 5 of 4150 rows
lon lat country continent piece
66.519 37.363 Afghanistan Asia p001
69.196 37.151 Afghanistan Asia p001
70.807 38.486 Afghanistan Asia p001
71.845 36.738 Afghanistan Asia p001
73.260 37.495 Afghanistan Asia p001
data(world_borders) + path + x(lon) + y(lat) + group(piece) +
  style(color = "#c9ccd6") +
  data(quakes_fiji) + point + x(east) + y(north) +
  style(color = "tomato", opacity = 0.35, size = 3) +
  globe(turn = 178, tilt = -18) + title("The map chapter's layers, kept round")
(data(world_borders) + path + x(col.lon) + y(col.lat) + group(col.piece) +
  style(color = "#c9ccd6") +
  data(quakes_fiji) + point + x(col.east) + y(col.north) +
  style(color = "tomato", opacity = 0.35, size = 3) +
  globe(turn = 178, tilt = -18) + title("The map chapter's layers, kept round"))
data(world_borders) + path + x(:lon) + y(:lat) + group(:piece) +
  style(color = "#c9ccd6") + data(quakes_fiji) + point + x(:east) +
  y(:north) + style(color = "tomato", opacity = 0.35, size = 3) +
  globe(turn = 178, tilt = -18) +
  title("The map chapter's layers, kept round")
plot(data(world_borders), path, x(col.lon), y(col.lat), group(col.piece),
  style({ color: "#c9ccd6" }), data(quakes_fiji), point, x(col.east),
  y(col.north), style({ color: "tomato", opacity: 0.35, size: 3 }),
  globe({ turn: 178, tilt: -18 }),
  title("The map chapter's layers, kept round"))
gog: 3192 of 4150 row(s) of `world_borders` face away from `globe(turn = 178, tilt = -18)` and are hidden behind the sphere. Turn to face them, or put a second view beside this one with `|`.
The map chapter's layers, kept round

“Given the world borders: paths, x is lon, y is lat, grouped by piece; then given quakes Fiji: points, x is east, y is north, on the globe.”

Read the message above the plot. Its count is out of 4150, the rows of world_borders. That table covers the whole earth, so any one view hides some of it. From this view most of its rows are on the far side of the earth, and every earthquake is on the near side. A second angle brings most of the hidden rows into view:

data(world_borders) + path + x(lon) + y(lat) + group(piece) +
  style(color = "#c9ccd6") +
  globe(turn = 20, tilt = 5) + title("The other side")
(data(world_borders) + path + x(col.lon) + y(col.lat) + group(col.piece) +
  style(color = "#c9ccd6") +
  globe(turn = 20, tilt = 5) + title("The other side"))
data(world_borders) + path + x(:lon) + y(:lat) + group(:piece) +
  style(color = "#c9ccd6") + globe(turn = 20, tilt = 5) +
  title("The other side")
plot(data(world_borders), path, x(col.lon), y(col.lat), group(col.piece),
  style({ color: "#c9ccd6" }), globe({ turn: 20, tilt: 5 }),
  title("The other side"))
The other side

36.3 The graticule

Every globe so far has drawn a grid of thin gray lines over the sphere. It is the graticule, this space’s gridlines. Its meridians run from pole to pole, one every thirty degrees of longitude, and its parallels circle the earth, one every thirty degrees of latitude. A flat panel draws its gridlines straight. A globe bends its gridlines onto the sphere, the way the polar space bends them into rings and spokes.

There are no axes beside the disk, because a sphere has no straight side to write one along. The graticule is the reference instead. theme(grid = ) works on it as on any other grid: "x" keeps only the meridians, "y" keeps only the parallels, and "none" removes it:

data(quakes_fiji) + point + x(east) + y(north) +
  globe(turn = 178, tilt = -18) + theme(grid = "none") +
  title("No graticule")
(data(quakes_fiji) + point + x(col.east) + y(col.north) +
  globe(turn = 178, tilt = -18) + theme(grid = "none") +
  title("No graticule"))
data(quakes_fiji) + point + x(:east) + y(:north) +
  globe(turn = 178, tilt = -18) + theme(grid = "none") +
  title("No graticule")
plot(data(quakes_fiji), point, x(col.east), y(col.north),
  globe({ turn: 178, tilt: -18 }), theme({ grid: "none" }),
  title("No graticule"))
No graticule

With the graticule off, nothing inside the disk shows where the poles are, or even that it is a sphere.

36.4 A route bends with the sphere

The graticule bends with the sphere, and so does everything else drawn on it. A route is the clearest case. On the map, path joins places with straight strokes. On the globe a straight route does not exist. The shortest way between two places bends with the surface, along a great circle: the line a tight string would take if you pulled it across the sphere between the two places. A path here follows it:

flight: all 2 rows
lon lat
139.69 35.69
-118.24 34.05
data(world_borders) + path + x(lon) + y(lat) + group(piece) +
  style(color = "#c9ccd6") +
  data(flight) + path + x(lon) + y(lat) +
  style(color = "#3d5a80", arrow = "end") +
  globe(turn = 178, tilt = -18) + title("Tokyo to Los Angeles")
(data(world_borders) + path + x(col.lon) + y(col.lat) + group(col.piece) +
  style(color = "#c9ccd6") +
  data(flight) + path + x(col.lon) + y(col.lat) +
  style(color = "#3d5a80", arrow = "end") +
  globe(turn = 178, tilt = -18) + title("Tokyo to Los Angeles"))
data(world_borders) + path + x(:lon) + y(:lat) + group(:piece) +
  style(color = "#c9ccd6") + data(flight) + path + x(:lon) + y(:lat) +
  style(color = "#3d5a80", arrow = "end") +
  globe(turn = 178, tilt = -18) + title("Tokyo to Los Angeles")
plot(data(world_borders), path, x(col.lon), y(col.lat), group(col.piece),
  style({ color: "#c9ccd6" }), data(flight), path, x(col.lon), y(col.lat),
  style({ color: "#3d5a80", arrow: "end" }),
  globe({ turn: 178, tilt: -18 }), title("Tokyo to Los Angeles"))
Tokyo to Los Angeles

“Given the world borders: paths, x is lon, y is lat, grouped by piece; then given the flight: a path, x is lon, y is lat, on the globe.”

Two rows describe that route, and the curve between them comes from the sphere. The arc bends toward the pole because that way is shorter. A route that keeps to one latitude is longer, unless that latitude is the equator.

36.5 Many routes are a network

That table held one route. One table can hold every route at once, and the sentence barely changes. Give each route a name, and give each of its two rows a longitude and a latitude. group() then splits the table into one arc per route, exactly as it split the world borders into pieces. A point layer marks the cities and a text layer names them. The picture this draws is a route network:

routes: first 5 of 14 rows
city route lon lat
Seoul Seoul-Tokyo 126.98 37.57
Seoul Seoul-Singapore 126.98 37.57
Seoul Seoul-Delhi 126.98 37.57
Tokyo Seoul-Tokyo 139.69 35.68
Tokyo Tokyo-Anchorage 139.69 35.68
cities: first 5 of 8 rows
city lon lat
Seoul 126.98 37.57
Tokyo 139.69 35.68
Singapore 103.82 1.35
Delhi 77.21 28.61
Cairo 31.24 30.04
data(world_borders) + path + x(lon) + y(lat) + group(piece) +
  style(color = "#c9ccd6") +
  data(routes) + path + x(lon) + y(lat) + group(route) +
  style(color = "#3d5a80", opacity = 0.6) +
  data(cities) + point + x(lon) + y(lat) +
  data(cities) + text + x(lon) + y(lat) + label(city) + style(nudge = "up") +
  globe(turn = 95, tilt = 30) + title("Routes between cities")
(data(world_borders) + path + x(col.lon) + y(col.lat) + group(col.piece) +
  style(color = "#c9ccd6") +
  data(routes) + path + x(col.lon) + y(col.lat) + group(col.route) +
  style(color = "#3d5a80", opacity = 0.6) +
  data(cities) + point + x(col.lon) + y(col.lat) +
  data(cities) + text + x(col.lon) + y(col.lat) + label(col.city) + style(nudge = "up") +
  globe(turn = 95, tilt = 30) + title("Routes between cities"))
data(world_borders) + path + x(:lon) + y(:lat) + group(:piece) +
  style(color = "#c9ccd6") + data(routes) + path + x(:lon) + y(:lat) +
  group(:route) + style(color = "#3d5a80", opacity = 0.6) + data(cities) +
  point + x(:lon) + y(:lat) + data(cities) + text + x(:lon) + y(:lat) +
  label(:city) + style(nudge = "up") + globe(turn = 95, tilt = 30) +
  title("Routes between cities")
plot(data(world_borders), path, x(col.lon), y(col.lat), group(col.piece),
  style({ color: "#c9ccd6" }), data(routes), path, x(col.lon), y(col.lat),
  group(col.route), style({ color: "#3d5a80", opacity: 0.6 }),
  data(cities), point, x(col.lon), y(col.lat), data(cities), text,
  x(col.lon), y(col.lat), label(col.city), style({ nudge: "up" }),
  globe({ turn: 95, tilt: 30 }), title("Routes between cities"))
gog: 897 of 4150 row(s) of `world_borders` face away from `globe(turn = 95, tilt = 30)` and are hidden behind the sphere. Turn to face them, or put a second view beside this one with `|`.
Seoul Tokyo Singapore Delhi Cairo London Anchorage Sydney Routes between cities

“Given the world borders: paths, x is lon, y is lat, grouped by piece; then given the routes: paths, x is lon, y is lat, grouped by route; then given the cities: points, x is lon, y is lat; then given the cities: text, x is lon, y is lat, label by city, on the globe.”

Every arc bends with the surface. The message above the plot counts the rows of one table only, the world borders, because gog prints a count only for a layer with rows the view hides. Every city and every arc faces this view. Dragging the globe in the web edition brings the hidden borders into view. A network between places needs nothing new from the grammar. The places give the positions, group() says which places are joined, and the sphere gives the shortest way between each pair.

Finding each city’s longitude and latitude and joining them to the routes is the host language’s job, as joining two tables was in the map chapter. What the sentence adds is only the layers: the routes, then the cities, then their names.

36.6 Meridians and parallels

The graticule draws the equator in the same thin gray as every other parallel. To give it a color of its own, draw it as a rule. A rule draws a line at one position and spans the other axis. On the map, a rule on latitude drew the equator as a straight line. The same sentence here draws it bent around the sphere:

equator: its one row
lat
0
data(world_borders) + path + x(lon) + y(lat) + group(piece) +
  style(color = "#c9ccd6") +
  data(equator) + rule + y(lat) + style(color = "#d4674f") +
  globe(turn = 20, tilt = 30) + title("The equator, bent around the sphere")
(data(world_borders) + path + x(col.lon) + y(col.lat) + group(col.piece) +
  style(color = "#c9ccd6") +
  data(equator) + rule + y(col.lat) + style(color = "#d4674f") +
  globe(turn = 20, tilt = 30) + title("The equator, bent around the sphere"))
data(world_borders) + path + x(:lon) + y(:lat) + group(:piece) +
  style(color = "#c9ccd6") + data(equator) + rule + y(:lat) +
  style(color = "#d4674f") + globe(turn = 20, tilt = 30) +
  title("The equator, bent around the sphere")
plot(data(world_borders), path, x(col.lon), y(col.lat), group(col.piece),
  style({ color: "#c9ccd6" }), data(equator), rule, y(col.lat),
  style({ color: "#d4674f" }), globe({ turn: 20, tilt: 30 }),
  title("The equator, bent around the sphere"))
The equator, bent around the sphere

“Given the world borders: paths, x is lon, y is lat, grouped by piece; then given the equator: a rule, y is lat, on the globe.”

A rule on y draws a parallel, as here, and a rule on x draws a meridian.

36.7 The choropleth, kept round

A rule and a path draw lines on the sphere. A fill has to cover a whole region instead, and the edge of the disk is where a fill is hardest to draw. A map that fills each region by a column of the table is a choropleth. The map chapter filled each country by its continent, and the same sentence fills the countries on the sphere:

data(world_borders) + zone + x(lon) + y(lat) + group(country) +
  color(continent) + globe(turn = 20, tilt = 5) +
  title("Every country, filled by continent")
(data(world_borders) + zone + x(col.lon) + y(col.lat) + group(col.country) +
  color(col.continent) + globe(turn = 20, tilt = 5) +
  title("Every country, filled by continent"))
data(world_borders) + zone + x(:lon) + y(:lat) + group(:country) +
  color(:continent) + globe(turn = 20, tilt = 5) +
  title("Every country, filled by continent")
plot(data(world_borders), zone, x(col.lon), y(col.lat),
  group(col.country), color(col.continent), globe({ turn: 20, tilt: 5 }),
  title("Every country, filled by continent"))
Every country, filled by continent Continent Asia Europe Africa South America Oceania North America Seven seas (open ocean)

“Given the world borders: zones, x is lon, y is lat, grouped by country, color by continent, on the globe.”

Look at the countries that the edge of the disk cuts through. gog closes each cut shape along that edge, so a half-visible country is still a filled region rather than an open outline.

36.8 Thousands of storm tracks on a dark globe

The routes earlier in this chapter were a few arcs between cities. A table of real records can hold thousands of lines, and then the lines are hard to tell apart. Thin lines drawn over one another on a pale sphere merge into one gray mass, and the lines inside it can no longer be followed.

cyclones is a table of that size. It holds all 2,174 storms from 1980 to 2025 that reached hurricane strength, a wind of at least 64 knots (119 kilometers per hour). The US National Oceanic and Atmospheric Administration (NOAA) keeps the record. Hurricanes, typhoons and cyclones are one kind of storm, with a different name in each ocean. Scientists call all three tropical cyclones, which gives the table its name.

Each row is one storm’s position at one moment, and a storm’s positions joined in order are its track. The positions are twelve hours apart. They cover only the time when the storm’s wind was at least 34 knots, or 63 kilometers per hour. At that speed a storm is given a name. category is the storm’s highest category on the Saffir-Simpson scale, which ranks a storm from 1 to 5 by its strongest wind. It holds one value for each storm, in three bands: “1 or 2”, “3 or 4” and “5”. The month column is not used in this chapter. The Play chapter uses it to show the same storms one calendar month at a time.

cyclones: first 5 of 29669 rows
storm month category lon lat
Peni 1980 Jan 1 or 2 173.5 -12.0
Peni 1980 Jan 1 or 2 174.4 -13.0
Peni 1980 Jan 1 or 2 175.0 -15.0
Peni 1980 Jan 1 or 2 175.8 -17.5
Peni 1980 Jan 1 or 2 178.0 -19.4

Three settings give the globe its dark look. theme(background = ) colors the sphere itself, here almost black, and grid = "none" removes the graticule. The land is the same zone layer as in the choropleth above. style(color = ) sets every country to one dark gray, so the continents stay darker than every track. Bright lines on a dark sphere do not merge into gray, so the thin tracks stay visible even where many of them cross:

data(world_borders) + zone + x(lon) + y(lat) + group(country) +
  style(color = "#1c2636") +
  data(cyclones) + path + x(lon) + y(lat) + group(storm) + color(category) +
  palette(c("mediumvioletred", "darkorange", "gold")) + style(opacity = 0.6) +
  globe(turn = 135, tilt = 10) + theme(background = "#050a14", grid = "none") +
  title("Every storm that reached hurricane strength, 1980 to 2025")
(data(world_borders) + zone + x(col.lon) + y(col.lat) + group(col.country) +
  style(color = "#1c2636") +
  data(cyclones) + path + x(col.lon) + y(col.lat) + group(col.storm) + color(col.category) +
  palette(["mediumvioletred", "darkorange", "gold"]) + style(opacity = 0.6) +
  globe(turn = 135, tilt = 10) + theme(background = "#050a14", grid = "none") +
  title("Every storm that reached hurricane strength, 1980 to 2025"))
data(world_borders) + zone + x(:lon) + y(:lat) + group(:country) +
  style(color = "#1c2636") + data(cyclones) + path + x(:lon) + y(:lat) +
  group(:storm) + color(:category) +
  palette(["mediumvioletred", "darkorange", "gold"]) +
  style(opacity = 0.6) + globe(turn = 135, tilt = 10) +
  theme(background = "#050a14", grid = "none") +
  title("Every storm that reached hurricane strength, 1980 to 2025")
plot(data(world_borders), zone, x(col.lon), y(col.lat),
  group(col.country), style({ color: "#1c2636" }), data(cyclones), path,
  x(col.lon), y(col.lat), group(col.storm), color(col.category),
  palette(["mediumvioletred", "darkorange", "gold"]),
  style({ opacity: 0.6 }), globe({ turn: 135, tilt: 10 }),
  theme({ background: "#050a14", grid: "none" }),
  title("Every storm that reached hurricane strength, 1980 to 2025"))
Every storm that reached hurricane strength, 1980 to 2025 Category 1 or 2 3 or 4 5

“Given the world borders: zones, x is lon, y is lat, grouped by country; then given the cyclones: paths, x is lon, y is lat, grouped by storm, colored by category, with a palette of mediumvioletred, darkorange and gold, on the globe.”

The busiest region is the western North Pacific, on both sides of the Philippines. A third of the storms began there, 729 of the 2,174, and so did 125 of the 221 storms that reached category 5. In the north, most tracks run west, and many then bend to the north and east. In the south, many bend to the south and east. The band along the equator stays empty: no position lies closer to it than 0.7 degrees, and only 33 of the 29,669 positions lie within 5 degrees of it.

The gold tracks lie on top because of the table’s order, not because of their color. gog draws the storms in the order the table lists them, and a track drawn later covers the tracks drawn before it. The table lists the category 5 storms last. Reverse the rows, and the gold tracks go to the bottom, under all the others.

36.9 A measure along the radius

On a flat map a quantity has to go on a channel, size or color, because both positions carry the place. The sphere leaves one direction free: the radius, which runs straight out from the surface. Every place on the sphere has its own radius. Here a bar is drawn at its place as a spike, rising outward along that radius, and z names the measure. Here the measure is reach, the square root of each country’s population:

population_spikes: first 5 of 120 rows
country lon lat people continent reach
Afghanistan 67.366280 34.59696 31889923 Asia 5647.116
Albania 20.165857 41.23771 3600523 Europe 1897.504
Algeria 2.743348 29.27604 33333216 Africa 5773.493
Angola 16.961080 -10.70456 12420476 Africa 3524.270
Argentina -65.436810 -38.39190 40301927 Americas 6348.380
data(world_borders) + path + x(lon) + y(lat) + group(piece) +
  style(color = "#c9ccd6") +
  data(population_spikes) + bar + x(lon) + y(lat) + z(reach) + color(continent) +
  globe(turn = 20, tilt = 12) +
  title("World population, one spike per country")
(data(world_borders) + path + x(col.lon) + y(col.lat) + group(col.piece) +
  style(color = "#c9ccd6") +
  data(population_spikes) + bar + x(col.lon) + y(col.lat) + z(col.reach) + color(col.continent) +
  globe(turn = 20, tilt = 12) +
  title("World population, one spike per country"))
data(world_borders) + path + x(:lon) + y(:lat) + group(:piece) +
  style(color = "#c9ccd6") + data(population_spikes) + bar + x(:lon) +
  y(:lat) + z(:reach) + color(:continent) + globe(turn = 20, tilt = 12) +
  title("World population, one spike per country")
plot(data(world_borders), path, x(col.lon), y(col.lat), group(col.piece),
  style({ color: "#c9ccd6" }), data(population_spikes), bar, x(col.lon),
  y(col.lat), z(col.reach), color(col.continent),
  globe({ turn: 20, tilt: 12 }),
  title("World population, one spike per country"))
World population, one spike per country Continent Asia Europe Africa Americas Oceania

“Given the world borders: paths, x is lon, y is lat, grouped by piece; then given the population spikes: bars, x is lon, y is lat, z is reach, colored by continent, on the globe.”

Look at the edge of the disk. The sphere itself can hide part of a spike. A spike just behind that edge has its base hidden, so only the part that rises past the edge is drawn. A spike too short to rise past that edge is not drawn at all. At the edge you see a spike from the side, along its whole length. A spike that points straight at you is seen from its tip, so it looks shorter than it is. In the web edition, turn the globe to see such a spike from the side.

Finding each country’s center and joining its population are the host language’s job, like the join for the cities above. Choosing how to scale the measure belongs there too. The square root keeps China’s spike from making every other spike too small to see. A scale keeps an axis in the column’s own units, and a globe draws no axis, so the globe refuses scale = on z().

36.10 The depth goes to the cube

The Fiji earthquakes from the chapter’s first plot carry a third number: elevation, their depth below the surface, written as a negative number. That number is not a height to raise above the surface. It is a third coordinate of the place itself, and on the globe z belongs to bar alone. So gog refuses the sentence below rather than guessing at it. The refusal names three things you can do instead: add a bar layer, drop z(), or draw the same table in the cube.

data(quakes_fiji) + point + x(east) + y(north) + z(elevation) +
  globe(turn = 178, tilt = -18)
(data(quakes_fiji) + point + x(col.east) + y(col.north) + z(col.elevation) +
  globe(turn = 178, tilt = -18))
data(quakes_fiji) + point + x(:east) + y(:north) + z(:elevation) +
  globe(turn = 178, tilt = -18)
plot(data(quakes_fiji), point, x(col.east), y(col.north),
  z(col.elevation), globe({ turn: 178, tilt: -18 }))
Error:
! gog: `z(...)` on a globe is the radius, and only a `bar` reads it — a spike standing at its place, measuring outward from the surface. Add a `bar` layer to raise spikes, drop `z(...)` to keep the marks drawn on the sphere, or drop `globe()` for the cube, where every position mark reads `z`.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.

A place with a depth belongs in the cube, the space with a third position. space() takes the same two arguments globe() does:

data(quakes_fiji) + point + x(east) + y(north) + z(elevation) +
  color(slab) + space(turn = 130, tilt = 25) +
  title("The same earthquakes, read by depth")
(data(quakes_fiji) + point + x(col.east) + y(col.north) + z(col.elevation) +
  color(col.slab) + space(turn = 130, tilt = 25) +
  title("The same earthquakes, read by depth"))
data(quakes_fiji) + point + x(:east) + y(:north) + z(:elevation) +
  color(:slab) + space(turn = 130, tilt = 25) +
  title("The same earthquakes, read by depth")
plot(data(quakes_fiji), point, x(col.east), y(col.north),
  z(col.elevation), color(col.slab), space({ turn: 130, tilt: 25 }),
  title("The same earthquakes, read by depth"))
185 180 175 170 165 -10 -20 -30 -200 -400 -600 East North Elevation The same earthquakes, read by depth Slab 0-90 km 90-180 km 180-270 km 270-360 km 360-450 km 450-540 km 540-630 km 630-720 km

“Given quakes Fiji: points, x is east, y is north, z is elevation, color by slab.”

slab names the depth band each earthquake falls in. The globe plots looked straight down on these earthquakes, so a deep one and a shallow one were drawn at almost the same place. In the cube, depth is a third position, so they separate. Most of them lie along one sloping sheet: the ocean floor, sinking into the earth. Drag this one too. The drag that turns the earth on a globe turns the cube here.

36.11 What a globe refuses

The map and the globe draw the same places as two pictures. The map flattens the sphere so a reader sees all of it at once. The globe keeps the sphere and hides the far half. To go from one picture to the other, you change one word.

The globe takes the map’s marks and one more: bar, which measures along the radius. It refuses the rest for the same reason the map does. Suppose you try a line through the earthquakes, as you would on a flat page. Both positions carry the place, exactly as on the map, and only bar reads the radius. So a line has no axis to measure along:

data(quakes_fiji) + line + x(east) + y(north) + globe()
data(quakes_fiji) + line + x(col.east) + y(col.north) + globe()
data(quakes_fiji) + line + x(:east) + y(:north) + globe()
plot(data(quakes_fiji), line, x(col.east), y(col.north), globe())
Error:
! gog: `line` measures along an axis, and a `globe()` plot has none to spare — longitude and latitude use both. Drop `globe()` to draw `line` flat, or use `point`, `bar`, `text`, `path`, `rule`, or `zone`. To carry a quantity on the globe, put it on a channel instead of an axis: `point + size(<column>)` sizes each place by it, and `color(<column>)` shades it.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.

The refusal’s advice is to put a quantity on a channel instead, size or color. On a globe a quantity can also be a spike’s length along the radius, as in the population spikes earlier in this chapter.

A latitude past a pole names no place, so a view cannot face that latitude:

data(quakes_fiji) + point + x(east) + y(north) + globe(tilt = 100)
data(quakes_fiji) + point + x(col.east) + y(col.north) + globe(tilt = 100)
data(quakes_fiji) + point + x(:east) + y(:north) + globe(tilt = 100)
plot(data(quakes_fiji), point, x(col.east), y(col.north),
  globe({ tilt: 100 }))
Error:
! gog: `globe(tilt = 100)` is outside -90 to 90, which is where a latitude lives. At 90 the view faces straight down on the north pole and at -90 on the south; there is no place past either. Use `globe(tilt = 90)` for the nearest view, or `globe(turn = )` to swing around the earth instead — a longitude wraps and a latitude does not.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.

And a globe draws no axes at all. So gog refuses an axis label rather than accepting it and drawing nothing:

data(quakes_fiji) + point + x(east) + y(north) + globe() + x_label("Longitude")
data(quakes_fiji) + point + x(col.east) + y(col.north) + globe() + x_label("Longitude")
data(quakes_fiji) + point + x(:east) + y(:north) + globe() +
  x_label("Longitude")
plot(data(quakes_fiji), point, x(col.east), y(col.north), globe(),
  x_label("Longitude"))
Error:
! gog: an axis label names an axis, and a `globe()` plot draws none — a sphere has no straight side to write one along, and the graticule is the reference instead. Drop it; `title()` still names the plot.
gog: nothing was rendered. Fix the above, or set GOG_STRICT=0 to draw anyway.

36.12 What comes next

A globe can draw a row only at the place its two numbers name. Network draws tables whose rows name no place, only a connection between two nodes, and the engine computes a position for every node.