3D earth and celestial bodies with PyVista in Python

The celestial objects and the cosmos are fascinating phenomena. There are a few libraries that allow us to be able to render such objects and that too, in 3D. One of them is called PyVista. In this Answer, we will look at how to visualize 3D Earth and the surrounding planets using this library. Let's drive straight ahead!

PyVista

PyVista is a pretty powerful Python library and is designed for data visualization specifically in three dimensions. It offers concise ways of creating both interactive and stunning 3D visuals. With PyVista, we can seamlessly render, analyze and manipulate 3D models, making it a great asset for a range of applications like research or engineering simulations.

PyVista logo
PyVista logo

Rendering 3D celestial objects

In this exploration, we will delve into code snippets that showcase the creation of breathtaking visualizations encompassing planets like Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and Neptune. We will render each planet separately first and then combine them together into a single visualization, all set against a backdrop of a high-resolution space-themed cube map.

Commonly used functions

Here are a few functions we will encounter in our visualizations, so let's go through them and understand them before starting with the code.

PyVista functions

Function

Explanation

pyvista.Light()

Creates a light source for illumination in the scene.

light.set_direction_angle(30, -20)

Sets the direction of the light source using angles.

examples.planets.load_*

Loads planet meshes and associated data from the examples module.

examples.planets.download_*_surface(texture=True)

Downloads textures for planet surfaces from the examples module.

examples.planets.load_saturn_rings

Loads a ring-shaped mesh (Saturn's rings) with specified parameters.

examples.planets.download_saturn_rings(texture=True)

Downloads the texture for Saturn's rings.

translate((-150000.0, 0.0, 0.0), inplace=True)

Translates a celestial body to a specific position.

pyvista.Plotter(lighting="none")

Initializes a Plotter object with specified lighting settings.

examples.download_cubemap_space_16k()

Downloads a high-resolution space-themed cubemap.

add_actor(cubemap.to_skybox())

Adds a skybox using the downloaded cubemap.

set_environment_texture(cubemap, True)

Sets the environment texture of the plot using the cubemap.

pl.add_light(light)

Adds the created light source to the plot for realistic illumination.

pl.add_mesh(celestial_body, texture=texture, smooth_shading=True)

Adds a celestial body mesh to the plot with texture and shading settings.

pl.show()

Displays the interactive 3D visualization in a browser.

Code implementation

Let's go through each planet one by one first and understand the rendering mechanism.

Mercury

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

mercury = examples.planets.load_mercury(radius=2439.0)
mercury_texture = examples.planets.download_mercury_surface(texture=True)

mercury.translate((0.0, 0.0, 0.0), inplace=True)

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()

_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(mercury, texture=mercury_texture, smooth_shading=True)

pl.show()

Code explanation

  • Lines 1–2: First, we import the modules we need. We specifically import the pyvista module and its example dataset using examples.

  • Lines 4–5: Next, we create a new Light object named light and set its direction angle to (30, -20) degrees. This is the light direction for our scene.

  • Lines 7–8: We then load the Mercury planet mesh using load_mercury from the example planets module. For the planet's surface, we'll have to download the Mercury surface texture using download_mercury_surface.

  • Line 10: We translate the Mercury mesh to a specific position in the scene i.e. placing the planet using the translate method with an (0.0, 0.0, 0.0) displacement.

  • Line 12: Moving forward, we create a Plotter object named pl for visualization. We specify that the lighting should be turned off for this plot.

  • Lines 14–16: To create a proper background, we download a space-themed cube map using download_cubemap_space_16k and add it as a skybox to our plot using the add_actor method.

  • Line 18: We set the environment texture of the plot to the previously downloaded cube map using set_environment_texture.

  • Line 20: Now, we add the light object to the plot using the add_light method. This provides a really realistic illumination of the scene.

  • Line 21: To show our planet, we add our Mercury mesh to the plot as a mesh with a texture applied to it. The smooth_shading parameter is set to True for a nicer display.

  • Line 22: Finally, we call the show method on our Plotter object pl to display the interactive plot in a browser. This will render the 3D scene with the Mercury planet and the specified lighting and environment setup.

Mercury output

Mercury visualization
Mercury visualization

The remaining planets

We can follow the above explanation and render the rest of the planets too. You can get the code for each planet below.

Venus

This code visualizes the planet Venus along with appropriate space lighting and a realistic space-themed background.

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

venus = examples.planets.load_venus(radius=6052.0)
venus_texture = examples.planets.download_venus_surface(texture=True)

venus.translate((-15000.0, 0.0, 0.0), inplace=True)

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()

_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(venus, texture=venus_texture, smooth_shading=True)

pl.show()

Venus output

Venus visualization
Venus visualization

Earth

This code visualizes our very own homeland, Earth, along with appropriate space lighting and a realistic space-themed background.

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

earth = examples.planets.load_earth(radius=6378.1)
earth_texture = examples.load_globe_texture()

earth.translate((-30000.0, 0.0, 0.0))

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()

_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(earth, texture=earth_texture, smooth_shading=True)

pl.show()

Earth output

Earth visualization
Earth visualization

Mars

This code visualizes the planet Mars along with appropriate space lighting and a realistic space-themed background.

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

mars = examples.planets.load_mars(radius=3397.2)
mars_texture = examples.planets.download_mars_surface(texture=True)

mars.translate((-30000.0, 0.0, 0.0), inplace=True)

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()

_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(mars, texture=mars_texture, smooth_shading=True)

pl.show()

Mars output

Mars visualization
Mars visualization

Jupiter

This code visualizes the planet Jupiter along with appropriate space lighting and a realistic space-themed background.

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

jupiter = examples.planets.load_jupiter(radius=71492.0)
jupiter_texture = examples.planets.download_jupiter_surface(texture=True)

jupiter.translate((-45000.0, 0.0, 0.0), inplace=True)

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()

_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(jupiter, texture=jupiter_texture, smooth_shading=True)

pl.show()

Jupiter output

Jupiter visualization
Jupiter visualization

Saturn

This is where things get interesting! To render Saturn, we'll add its rings within the visualization.

For this purpose, we can use the following parameters for our examples.planets.load_saturn_rings() function:

  • inner specifies the inner radius of the rings.

  • outer specifies the outer radius of the rings.

  • c_res specifies the resolution of the rings i.e., the number of segments used to create the ring.

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

saturn = examples.planets.load_saturn(radius=60268.0)
saturn_texture = examples.planets.download_saturn_surface(texture=True)

inner = 60268.0 + 7000.0
outer = 60268.0 + 80000.0
saturn_rings = examples.planets.load_saturn_rings(inner=inner, outer=outer, c_res=50)
saturn_rings_texture = examples.planets.download_saturn_rings(texture=True)

saturn.translate((-150000.0, 0.0, 0.0), inplace=True)
saturn_rings.translate((-150000.0, 0.0, 0.0), inplace=True)

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()

_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(saturn, texture=saturn_texture, smooth_shading=True)
pl.add_mesh(saturn_rings, texture=saturn_rings_texture, smooth_shading=True)

pl.show()

Saturn output

Saturn visualization
Saturn visualization

Uranus

This code visualizes the planet Uranus along with appropriate space lighting and a realistic space-themed background.

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

uranus = examples.planets.load_uranus(radius=25559.0)
uranus_texture = examples.planets.download_uranus_surface(texture=True)

uranus.translate((-400000.0, 0.0, 0.0), inplace=True)

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()

_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(uranus, texture=uranus_texture, smooth_shading=True)

pl.show()

Uranus output

Uranus visualization
Uranus visualization

Neptune

This code visualizes the planet Neptune along with appropriate space lighting and a realistic space-themed background.

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

neptune = examples.planets.load_neptune(radius=24764.0)
neptune_texture = examples.planets.download_neptune_surface(texture=True)

neptune.translate((-600000.0, 0.0, 0.0), inplace=True)

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()

_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(neptune, texture=neptune_texture, smooth_shading=True)

pl.show()

Neptune output

Neptune visualization
Neptune visualization

The planets all together

Having learned how to visualize the different planets separately, we can combine the codes and create a space scene with all of the planets together. This allows us to visualize the differences in their relative sizes as well.

import pyvista
from pyvista import examples

light = pyvista.Light()
light.set_direction_angle(30, -20)

mercury = examples.planets.load_mercury(radius=2449.0)
venus = examples.planets.load_venus(radius=6062.0)
earth = examples.planets.load_earth(radius=6388.1)
mars = examples.planets.load_mars(radius=3407.2)
jupiter = examples.planets.load_jupiter(radius=71502.0)
saturn = examples.planets.load_saturn(radius=60278.0)
uranus = examples.planets.load_uranus(radius=25669.0)
neptune = examples.planets.load_neptune(radius=24874.0)

inner = 60268.0 + 7000.0
outer = 60268.0 + 80000.0
saturn_rings = examples.planets.load_saturn_rings(inner=inner, outer=outer, c_res=50)
saturn_rings_texture = examples.planets.download_saturn_rings(texture=True)

mercury_texture = examples.planets.download_mercury_surface(texture=True)
venus_texture = examples.planets.download_venus_surface(texture=True)
earth_texture = examples.load_globe_texture()
mars_texture = examples.planets.download_mars_surface(texture=True)
jupiter_texture = examples.planets.download_jupiter_surface(texture=True)
saturn_texture = examples.planets.download_saturn_surface(texture=True)
saturn_rings_texture = examples.planets.download_saturn_rings(texture=True)
uranus_texture = examples.planets.download_uranus_surface(texture=True)
neptune_texture = examples.planets.download_neptune_surface(texture=True)

mercury.translate((10.0, 0.0, 0.0), inplace=True)
venus.translate((-15015.0, 0.0, 0.0), inplace=True)
earth.translate((-30030.0, 0.0, 0.0), inplace=True)
mars.translate((-45045.0, 0.0, 0.0), inplace=True)
jupiter.translate((-150150.0, 0.0, 0.0), inplace=True)
saturn.translate((-400400.0, 0.0, 0.0), inplace=True)
saturn_rings.translate((-400400.0, 0.0, 0.0), inplace=True)
uranus.translate((-600600.0, 0.0, 0.0), inplace=True)
neptune.translate((-700700.0, 0.0, 0.0), inplace=True)

pl = pyvista.Plotter(lighting="none")

cubemap = examples.download_cubemap_space_16k()
_ = pl.add_actor(cubemap.to_skybox())

pl.set_environment_texture(cubemap, True)

pl.add_light(light)
pl.add_mesh(mercury, texture=mercury_texture, smooth_shading=True)
pl.add_mesh(venus, texture=venus_texture, smooth_shading=True)
pl.add_mesh(earth, texture=earth_texture, smooth_shading=True)
pl.add_mesh(mars, texture=mars_texture, smooth_shading=True)
pl.add_mesh(jupiter, texture=jupiter_texture, smooth_shading=True)
pl.add_mesh(saturn, texture=saturn_texture, smooth_shading=True)
pl.add_mesh(saturn_rings, texture=saturn_rings_texture, smooth_shading=True)
pl.add_mesh(uranus, texture=uranus_texture, smooth_shading=True)
pl.add_mesh(neptune, texture=neptune_texture, smooth_shading=True)

pl.show()

Code explanation

  • Lines 1–2: First and foremost, we import our necessary modules.

  • Lines 4–5: A new Light object named light is created, and its direction angle is set to (30, -20) degrees to determine the lighting direction.

  • Lines 7–14: We load various planet meshes such as Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and Neptune using the load_* functions from the example planets module.

  • Lines 16–19: For our Saturn rendering, we define the inner and outer radii of its rings and load a ring-shaped mesh using load_saturn_rings. For the texture of the rings, we use download_saturn_rings(texture=True).

  • Lines 21–29: Next, we also download textures for each planet using the download_*_surface(texture=True) functions.

  • Lines 31–39: Each planet is translated to a specific position in the scene using the translate method. We do this by specifying different offsets.

  • Line 41: A Plotter object pl is created for visualization.

  • Lines 43–44: We use a high-resolution space-themed cube map for the background using download_cubemap_space_16k and add it as a skybox using add_actor.

  • Line 46: The environment texture of the plot is set to it using set_environment_texture.

  • Line 48: The light object we created is added to the plot.

  • Lines 49–57: Our planets are now ready! Each planet mesh is added to the plot with its respective texture applied and with smooth shading for a smooth appearance.

  • Line 59: Finally, show is called on pl to display our amazing visualization.

Note: These codes require extensive processing so they may take a while to run and render an empty screen initially during processing.

Demonstration

The rendered 3D scene showcases all the planets, their rings, and the customized lighting and environment setup.

Use cases

Celestial body rendering can be used in several cases like the ones mentioned below.

Engineering simulation

Engineers can use this visualization approach to simulate the movement and different positions of celestial bodies.

Education

PyVista can help educators design astronomy lessons by visualizing planetary properties like relative sizes, rotations, etc.

Virtual planetariums

An interesting application would be to power virtual planetarium applications, offering users an interactive tour of the solar system and beyond.

Conclusively, PyVista allows us to explore Earth and celestial bodies in a pretty visually appealing and interactive manner. The combination of planetary meshes, textures, lighting, and environment settings allows us to witness a realistic depiction of the cosmos.

How well do you know PyVista’s celestial visualization?

Question

What’s different between rendering other planets and Saturn?

Show Answer

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved