One of the easiest ways to interact with yt is by creating simple visualizations of your data. Below we show how to do this, as well as how to extend these plots to be ready for publication.
This script shows the simplest way to make a slice through a dataset. See Slice Plots for more information.
import yt
# Load the dataset.
ds = yt.load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150")
# Create density slices in all three axes.
yt.SlicePlot(ds, 'x', "density", width = (800.0, 'kpc')).save()
yt.SlicePlot(ds, 'y', "density", width = (800.0, 'kpc')).save()
yt.SlicePlot(ds, 'z', "density", width = (800.0, 'kpc')).save()
This is the simplest way to make a projection through a dataset. There are several different Types of Projections, but non-weighted line integrals and weighted line integrals are the two most common. Here we create density projections (non-weighted line integral). See Projection Plots for more information.
import yt
# Load the dataset.
ds = yt.load("GalaxyClusterMerger/fiducial_1to3_b0.273d_hdf5_plt_cnt_0175")
# Create projections of the density (non-weighted line integrals).
yt.ProjectionPlot(ds, "x", "density").save()
yt.ProjectionPlot(ds, "y", "density").save()
yt.ProjectionPlot(ds, "z", "density").save()
And here we produce density-weighted temperature projections (weighted line integral) for the same dataset as the non-weighted projections above. See Projection Plots for more information.
(simple_projection_weighted.py)
import yt
# Load the dataset.
ds = yt.load("GalaxyClusterMerger/fiducial_1to3_b0.273d_hdf5_plt_cnt_0175")
# Create density-weighted projections of temperature (weighted line integrals)
yt.ProjectionPlot(ds, "x", "temperature", weight_field="density").save()
yt.ProjectionPlot(ds, "y", "temperature", weight_field="density").save()
yt.ProjectionPlot(ds, "z", "temperature", weight_field="density").save()
This demonstrates how to make a phase plot. Phase plots can be thought of as two-dimensional histograms, where the value is either the weighted-average or the total accumulation in a cell. See 2D Phase Plots for more information.
import yt
# Load the dataset.
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
# Create a sphere of radius 100 kpc in the center of the domain.
my_sphere = ds.sphere("c", (100.0, "kpc"))
# Create a PhasePlot object.
# Setting weight to None will calculate a sum.
# Setting weight to a field will calculate an average
# weighted by that field.
plot = yt.PhasePlot(my_sphere, "density", "temperature", "cell_mass",
weight_field=None)
# Set the units of mass to be in solar masses (not the default in cgs)
plot.set_unit('cell_mass', 'Msun')
# Save the image.
# Optionally, give a string as an argument
# to name files with a keyword.
plot.save()
Often, one wants to examine the distribution of one variable as a function of another. This shows how to see the distribution of mass in a simulation, with respect to the total mass in the simulation. See 2D Phase Plots for more information.
import yt
# Load the dataset.
ds = yt.load("GalaxyClusterMerger/fiducial_1to3_b0.273d_hdf5_plt_cnt_0175")
# Create a data object that represents the whole box.
ad = ds.all_data()
# This is identical to the simple phase plot, except we supply
# the fractional=True keyword to divide the profile data by the sum.
plot = yt.PhasePlot(ad, "density", "temperature", "cell_mass",
weight_field=None, fractional=True)
# Save the image.
# Optionally, give a string as an argument
# to name files with a keyword.
plot.save()
This is a “profile,” which is a 1D histogram. This can be thought of as either
the total accumulation (when weight_field is set to None
) or the average
(when a weight_field is supplied.)
See 1D Profile Plots for more information.
import yt
# Load the dataset.
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
# Create a 1D profile within a sphere of radius 100 kpc
# of the average temperature and average velocity_x
# vs. density, weighted by mass.
sphere = ds.sphere("c", (100., "kpc"))
plot = yt.ProfilePlot(sphere, "density", ["temperature", "velocity_x"],
weight_field="cell_mass")
plot.set_log("velocity_x", False)
# Save the image.
# Optionally, give a string as an argument
# to name files with a keyword.
plot.save()
This shows how to make a profile of a quantity with respect to the radius. See 1D Profile Plots for more information.
import yt
# Load the dataset.
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
# Create a sphere of radius 100 kpc in the center of the box.
my_sphere = ds.sphere("c", (100.0, "kpc"))
# Create a profile of the average density vs. radius.
plot = yt.ProfilePlot(my_sphere, "radius", "density",
weight_field="cell_mass")
# Change the units of the radius into kpc (and not the default in cgs)
plot.set_unit('radius', 'kpc')
# Save the image.
# Optionally, give a string as an argument
# to name files with a keyword.
plot.save()
This is a simple example of overplotting multiple 1D profiles from a number of datasets to show how they evolve over time. See 1D Profile Plots for more information.
import yt
# Create a time-series object.
sim = yt.simulation("enzo_tiny_cosmology/32Mpc_32.enzo", "Enzo")
sim.get_time_series(redshifts=[5, 4, 3, 2, 1, 0])
# Lists to hold profiles, labels, and plot specifications.
profiles = []
labels = []
plot_specs = []
# Loop over each dataset in the time-series.
for ds in sim:
# Create a data container to hold the whole dataset.
ad = ds.all_data()
# Create a 1d profile of density vs. temperature.
profiles.append(yt.create_profile(ad, ["density"],
fields=["temperature"]))
# Add labels and linestyles.
labels.append("z = %.2f" % ds.current_redshift)
plot_specs.append(dict(linewidth=2, alpha=0.7))
# Create the profile plot from the list of profiles.
plot = yt.ProfilePlot.from_profiles(profiles, labels=labels,
plot_specs=plot_specs)
# Save the image.
plot.save()
This shows how to plot the variance for a 1D profile. In this example, we manually create a 1D profile object, which gives us access to the variance data. See 1D Profile Plots for more information.
import matplotlib.pyplot as plt
import yt
# Load the dataset.
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
# Create a sphere of radius 1 Mpc centered on the max density location.
sp = ds.sphere("max", (1, "Mpc"))
# Calculate and store the bulk velocity for the sphere.
bulk_velocity = sp.quantities.bulk_velocity()
sp.set_field_parameter('bulk_velocity', bulk_velocity)
# Create a 1D profile object for profiles over radius
# and add a velocity profile.
prof = yt.create_profile(sp, 'radius', ('gas', 'velocity_magnitude'),
units = {'radius': 'kpc'},
extrema = {'radius': ((0.1, 'kpc'), (1000.0, 'kpc'))},
weight_field='cell_mass')
# Create arrays to plot.
radius = prof.x.value
mean = prof['gas', 'velocity_magnitude'].value
variance = prof.variance['gas', 'velocity_magnitude'].value
# Plot the average velocity magnitude.
plt.loglog(radius, mean, label='Mean')
# Plot the variance of the velocity magnitude.
plt.loglog(radius, variance, label='Standard Deviation')
plt.xlabel('r [kpc]')
plt.ylabel('v [cm/s]')
plt.legend()
plt.savefig('velocity_profiles.png')
By adding multiple fields to a single
SlicePlot
or
ProjectionPlot
some of the overhead of
creating the data object can be reduced, and better performance squeezed out.
This recipe shows how to add multiple fields to a single plot.
See Slice Plots and Projection Plots for more information.
(simple_slice_with_multiple_fields.py)
import yt
# Load the dataset
ds = yt.load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150")
# Create density slices of several fields along the x axis
yt.SlicePlot(ds, 'x', ['density','temperature','pressure'],
width = (800.0, 'kpc')).save()
One can create slices from any arbitrary angle, not just those aligned with the x,y,z axes. See Off Axis Slices for more information.
import yt
# Load the dataset.
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
# Create a 15 kpc radius sphere, centered on the center of the sim volume
sp = ds.sphere("center", (15.0, "kpc"))
# Get the angular momentum vector for the sphere.
L = sp.quantities.angular_momentum_vector()
print("Angular momentum vector: {0}".format(L))
# Create an OffAxisSlicePlot of density centered on the object with the L
# vector as its normal and a width of 25 kpc on a side
p = yt.OffAxisSlicePlot(ds, L, "density", sp.center, (25, "kpc"))
p.save()
Like off-axis slices, off-axis projections can be created from any arbitrary viewing angle. See Off Axis Projection Plots for more information.
(simple_off_axis_projection.py)
import yt
# Load the dataset.
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
# Create a 15 kpc radius sphere, centered on the center of the sim volume
sp = ds.sphere("center", (15.0, "kpc"))
# Get the angular momentum vector for the sphere.
L = sp.quantities.angular_momentum_vector()
print("Angular momentum vector: {0}".format(L))
# Create an OffAxisProjectionPlot of density centered on the object with the L
# vector as its normal and a width of 25 kpc on a side
p = yt.OffAxisProjectionPlot(ds, L, "density", sp.center, (25, "kpc"))
p.save()
You can also use yt to make particle-only plots. This script shows how to plot all the particle x and y positions in a dataset, using the particle mass to set the color scale. See Particle Plots for more information.
import yt
# load the dataset
ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
# create our plot
p = yt.ParticlePlot(ds, 'particle_position_x', 'particle_position_y', 'particle_mass', width=(0.5, 0.5))
# pick some appropriate units
p.set_axes_unit('kpc')
p.set_unit('particle_mass', 'Msun')
#save result
p.save()
You are not limited to plotting spatial fields on the x and y axes. This example shows how to plot the particle x-coordinates versus their z-velocities, again using the particle mass to set the colorbar. See Particle Plots for more information.
import yt
# load the dataset
ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
# create our plot
p = yt.ParticlePlot(ds, 'particle_position_x', 'particle_velocity_z', ['particle_mass'])
# pick some appropriate units
p.set_unit('particle_position_x', 'Mpc')
p.set_unit('particle_velocity_z', 'km/s')
p.set_unit('particle_mass', 'Msun')
# save result
p.save()
If you don’t want to display a third field on the color bar axis, simply pass in a color string instead of a particle field. See Particle Plots for more information.
import yt
# load the dataset
ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
# create our plot
p = yt.ParticlePlot(ds, 'particle_position_x', 'particle_position_y', color='b')
# zoom in a little bit
p.set_width(500, 'kpc')
#save result
p.save()
Volume renderings are 3D projections rendering isocontours in any arbitrary field (e.g. density, temperature, pressure, etc.) See Volume Rendering: Making 3D Photorealistic Isocontoured Images for more information.
import yt
import numpy as np
# Load the dataset.
ds = yt.load("Enzo_64/DD0043/data0043")
# Create a data container (like a sphere or region) that
# represents the entire domain.
ad = ds.all_data()
# Get the minimum and maximum densities.
mi, ma = ad.quantities.extrema("density")
# Create a transfer function to map field values to colors.
# We bump up our minimum to cut out some of the background fluid
tf = yt.ColorTransferFunction((np.log10(mi)+1, np.log10(ma)))
# Add five Gaussians, evenly spaced between the min and
# max specified above with widths of 0.02 and using the
# spectral colormap.
tf.add_layers(5, w=0.02, colormap="spectral")
# Choose a center for the render.
c = [0.5, 0.5, 0.5]
# Choose a vector representing the viewing direction.
L = [0.5, 0.2, 0.7]
# Set the width of the image.
# Decreasing or increasing this value
# results in a zoom in or out.
W = 1.0
# The number of pixels along one side of the image.
# The final image will have Npixel^2 pixels.
Npixels = 512
# Create a camera object.
# This object creates the images and
# can be moved and rotated.
cam = ds.camera(c, L, W, Npixels, tf)
# Create a snapshot.
# The return value of this function could also be accepted, modified (or saved
# for later manipulation) and then put written out using write_bitmap.
# clip_ratio applies a maximum to the function, which is set to that value
# times the .std() of the array.
cam.snapshot("%s_volume_rendered.png" % ds, clip_ratio=8.0)
This example illustrates how to create a SlicePlot and then suppress the axes labels and colorbars. This is useful when you don’t care about the physical scales and just want to take a closer look at the raw plot data. See Hiding the Colorbar and Axis Labels for more information.
import yt
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
slc = yt.SlicePlot(ds, "x", "density")
slc.save("default_sliceplot.png")
slc.hide_axes()
slc.save("no_axes_sliceplot.png")
slc.hide_colorbar()
slc.save("no_axes_no_colorbar_sliceplot.png")
slc.show_axes()
slc.save("no_colorbar_sliceplot.png")
While often the Plot Window, and its affiliated Plot Modifications: Overplotting Contours, Velocities, Particles, and More can
cover normal use cases, sometimes more direct access to the underlying
Matplotlib engine is necessary. This recipe shows how to modify the plot
window matplotlib.axes.Axes
object directly.
See Further customization via matplotlib for more information.
(simple_slice_matplotlib_example.py)
import yt
import numpy as np
# Load the dataset.
ds = yt.load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150")
# Create a slice object
slc = yt.SlicePlot(ds,'x','density',width=(800.0,'kpc'))
# Get a reference to the matplotlib axes object for the plot
ax = slc.plots['density'].axes
# Let's adjust the x axis tick labels
for label in ax.xaxis.get_ticklabels():
label.set_color('red')
label.set_fontsize(16)
# Get a reference to the matplotlib figure object for the plot
fig = slc.plots['density'].figure
# And create a mini-panel of a gaussian histogram inside the plot
rect = (0.2,0.2,0.2,0.2)
new_ax = fig.add_axes(rect)
n, bins, patches = new_ax.hist(np.random.randn(1000)+20, 50,
facecolor='black', edgecolor='black')
# Make sure its visible
new_ax.tick_params(colors='white')
# And label it
la = new_ax.set_xlabel('Dinosaurs per furlong')
la.set_color('white')
slc.save()
yt has sensible defaults for colormaps, but there are over a hundred available for customizing your plots. Here we generate a projection and then change its colormap. See Colormaps for a list and for images of all the available colormaps.
import yt
# Load the dataset
ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
# Create a projection and save it with the default colormap ('algae')
p = yt.ProjectionPlot(ds, "z", "density", width=(100, 'kpc'))
p.save()
# Change the colormap to 'jet' and save again. We must specify
# a different filename here or it will save it over the top of
# our first projection.
p.set_cmap(field="density", cmap='jet')
p.save('proj_with_jet_cmap.png')
# Change the colormap to 'hot' and save again.
p.set_cmap(field="density", cmap='hot')
p.save('proj_with_hot_cmap.png')
Here we see how to take an image and save it using different background colors.
In this case we use the Simple Volume Rendering recipe to generate the image, but it works for any NxNx4 image array (3 colors and 1 opacity channel). See Volume Rendering: Making 3D Photorealistic Isocontoured Images for more information.
# This shows how to save ImageArray objects, such as those returned from
# volume renderings, to pngs with varying backgrounds.
# First we use the simple_volume_rendering.py recipe from above to generate
# a standard volume rendering. The only difference is that we use
# grey_opacity=True with our TransferFunction, as the colored background
# functionality requires images with an opacity between 0 and 1.
# We have removed all the comments from the volume rendering recipe for
# brevity here, but consult the recipe for more details.
import yt
import numpy as np
ds = yt.load("Enzo_64/DD0043/data0043")
ad = ds.all_data()
mi, ma = ad.quantities.extrema("density")
tf = yt.ColorTransferFunction((np.log10(mi)+1, np.log10(ma)), grey_opacity=True)
tf.add_layers(5, w=0.02, colormap="spectral")
c = [0.5, 0.5, 0.5]
L = [0.5, 0.2, 0.7]
W = 1.0
Npixels = 512
cam = ds.camera(c, L, W, Npixels, tf)
im = cam.snapshot("original.png" % ds, clip_ratio=8.0)
# Our image array can now be transformed to include different background
# colors. By default, the background color is black. The following
# modifications can be used on any image array.
# write_png accepts a background keyword argument that defaults to 'black'.
# Other choices include:
# black (0.,0.,0.,1.)
# white (1.,1.,1.,1.)
# None (0.,0.,0.,0.) <-- Transparent!
# any rgba list/array: [r,g,b,a], bounded by 0..1
# We include the clip_ratio=8 keyword here to bring out more contrast between
# the background and foreground, but it is entirely optional.
im.write_png('black_bg.png', background='black', clip_ratio=8.0)
im.write_png('white_bg.png', background='white', clip_ratio=8.0)
im.write_png('green_bg.png', background=[0.,1.,0.,1.], clip_ratio=8.0)
im.write_png('transparent_bg.png', background=None, clip_ratio=8.0)
It can be useful to add annotations to plots to show off certain features and make it easier for your audience to understand the plot’s purpose. There are a variety of available plot modifications one can use to add annotations to their plots. Below includes just a handful, but please look at the other plot modifications to get a full description of what you can do to highlight your figures.
import yt
ds = yt.load("enzo_tiny_cosmology/DD0046/DD0046")
p = yt.ProjectionPlot(ds, "z", "density")
p.annotate_sphere([0.54,0.72], radius=(1, 'Mpc'), coord_system='axis', text='Halo #7')
p.annotate_sphere([0.65,0.38,0.3], radius=(1.5, 'Mpc'), coord_system='data', circle_args={'color':'green', 'linewidth':4, 'linestyle':'dashed'})
p.annotate_arrow([0.87,0.59,0.2], coord_system='data', plot_args={'color':'red'})
p.annotate_text([10,20], 'Some halos', coord_system='plot')
p.annotate_marker([0.45,0.1,0.4], coord_system='data',
plot_args={'color':'yellow', 's':500})
p.annotate_line([0.2,0.4], [0.3,0.9], coord_system='axis')
p.annotate_timestamp(redshift=True)
p.annotate_scale()
p.save()
When creating movies of multiple outputs from the same simulation (see Time Series Analysis), it can be helpful to include a timestamp and the physical scale of each individual output. This is simply achieved using the annotate_timestamp() and annotate_scale() callbacks on your plots. For more information about similar plot modifications using other callbacks, see the section on Plot Modifications.
(annotate_timestamp_and_scale.py)
import yt
ts = yt.load("enzo_tiny_cosmology/DD000?/DD000?")
for ds in ts:
p = yt.ProjectionPlot(ds, "z", "density")
p.annotate_timestamp(corner='upper_left', redshift=True, draw_inset_box=True)
p.annotate_scale(corner='upper_right')
p.save()