"""Plots for radial profiles
For more information, see the :ref:`profile` tutorial.
.. versionchanged :: 2.0
The ``fourier_profile`` routine has been removed.
Call signatures for the other two functions have been cleared up (see below).
"""
import logging
import matplotlib.pyplot as plt
import numpy as np
from .. import transformation
from ..analysis import angmom, halo, profile
logger = logging.getLogger('pynbody.plot.profile')
[docs]
def rotation_curve(sim, center=True, r_units='kpc',
v_units='km s^-1', nbins=50, bin_spacing='log', quick=False,
rmin=None, rmax=None, parts=False, **kwargs):
"""Generate and plot a rotation curve.
This routine centres and aligns the disk into the x-y plane, then uses
the potential in that plane to generate and plot a rotation curve.
The transformation of the simulation is then reverted to its original
state.
.. versionchanged :: 2.0
The transformation of the simulation is now reverted when the routine exits. Previously,
the transformation was left in place.
The *clear*, *axes*, *legend*, *filename* and *yrange* keywords have been removed for consistency with
the rest of the plotting routines. Use the matplotlib functions directly to save the figure
or modify the axes.
Parameters
----------
sim : pynbody.snapshot.SimSnap
The simulation snapshot to be used.
center : bool, optional
If True (default), the simulation is centered and rotated so that the disk is in the x-y plane. If False,
the simulation is assumed to be pre-centred and already aligned.
quick : bool, optional
If True, the rotation curve is calculated using a spherical approximation to the circular velocity.
If False (default), the rotation curve is calculated using 3D forces.
bin_spacing : str, optional
The type of bin spacing to use in the profile. See :class:`~pynbody.analysis.profile.Profile` for details.
rmin : float, optional
The minimum radius to use in the profile. Default is the minimum radius in the simulation.
rmax : float, optional
The maximum radius to use in the profile. Default is the maximum radius in the simulation.
nbins : int, optional
The number of bins to use in the profile. Default is 50.
r_units : str, optional
The units in which to plot the radial axis. Default is 'kpc'.
v_units : str, optional
The units in which to plot the velocity axis. Default is 'km s^-1'.
parts : bool, optional
If True, the rotation curve is calculated and plotted for each particle type separately. Default is False.
min : float, optional
Deprecated. Use rmin instead.
max : float, optional
Deprecated. Use rmax instead.
Returns
-------
r : pynbody.array.SimArray
The radial bins used in the profile.
v : pynbody.array.SimArray
The circular velocity profile
"""
if 'min' in kwargs:
rmin = kwargs.pop('min')
logger.warning("The 'min' keyword is deprecated. Use 'rmin' instead.", DeprecationWarning)
if 'max' in kwargs:
rmax = kwargs.pop('max')
logger.warning("The 'max' keyword is deprecated. Use 'rmax' instead.", DeprecationWarning)
if center:
trans = angmom.faceon(sim)
else:
trans = transformation.NullTransformation(sim)
with trans:
if rmin is None:
rmin = sim['rxy'].min()
if rmax is None:
rmax = sim['rxy'].max()
pro = profile.Profile(sim, type=bin_spacing, nbins=nbins,
rmin =rmin, rmax =rmax)
r = pro['rbins'].in_units(r_units)
if quick:
v = pro['rotation_curve_spherical'].in_units(v_units)
else:
v = pro['v_circ'].in_units(v_units)
if parts:
plt.plot(r, v, label='total', **kwargs)
gpro = profile.Profile(sim.gas, type=bin_spacing, nbins=nbins,
rmin =rmin, rmax =rmax)
dpro = profile.Profile(sim.dark, type=bin_spacing, nbins=nbins,
rmin =rmin, rmax =rmax)
spro = profile.Profile(sim.star, type=bin_spacing, nbins=nbins,
rmin =rmin, rmax =rmax)
if quick:
gv = gpro['rotation_curve_spherical'].in_units(v_units)
dv = dpro['rotation_curve_spherical'].in_units(v_units)
sv = spro['rotation_curve_spherical'].in_units(v_units)
else:
gv = gpro['v_circ'].in_units(v_units)
dv = dpro['v_circ'].in_units(v_units)
sv = spro['v_circ'].in_units(v_units)
plt.plot(gpro['rbins'].in_units(r_units), gv, "--", label="gas")
plt.plot(dpro['rbins'].in_units(r_units), dv, label="dark")
plt.plot(spro['rbins'].in_units(r_units), sv, linestyle="dotted", label="star")
else:
plt.plot(r, v, **kwargs)
plt.xlabel("r / $" + r.units.latex() + "$", fontsize='large')
plt.ylabel("v$_c / " + v.units.latex() + '$', fontsize='large')
return r, v
[docs]
def density_profile(sim, center=True, r_units=None, rho_units=None,
rmin=None, rmax=None, nbins=50, bin_spacing='log', **kwargs):
"""Generate and plot a 3D density profile with error-bars.
This routine centers the simulation and generates a 3D density profile with error-bars. It then undoes the
centering transformation before returning.
.. versionchanged :: 2.0
The transformation of the simulation is now reverted when the routine exits. Previously,
the transformation was left in place.
The y-axis is no longer scaled to the critical density by default. Specify the units using the *in_units* keyword.
The x-axis is no longer scaled to kpc by default. Specify the units using the *r_units* keyword.
The *clear*, *axes*, *filename*, *fit* and *fit_factor* keywords have been removed for consistency with
the rest of the plotting routines. Use the matplotlib functions directly to save the figure
or modify the axes.
Parameters
----------
sim : pynbody.snapshot.SimSnap
The simulation snapshot to be used.
center : bool, optional
If True (default), the simulation is centered. If False, the simulation is assumed to be pre-centered.
r_units : str, optional
The units in which to plot the radial axis. Default is None (no conversion).
rho_units : str, optional
The units in which to plot the density axis. Default is None (no conversion).
rmin : float, optional
The minimum radius to use in the profile. Default is the minimum radius in the simulation.
rmax : float, optional
The maximum radius to use in the profile. Default is the maximum radius in the simulation.
nbins : int, optional
The number of bins to use in the profile. Default is 50.
bin_spacing : str, optional
The type of bin spacing to use in the profile. See :class:`~pynbody.analysis.profile.Profile` for details.
**kwargs : dict
Additional keyword arguments are passed to :func:`matplotlib.pyplot.errorbar`.
"""
if 'min' in kwargs:
rmin = kwargs.pop('min')
logger.warning("The 'min' keyword is deprecated. Use 'rmin' instead.", DeprecationWarning)
if 'max' in kwargs:
rmax = kwargs.pop('max')
logger.warning("The 'max' keyword is deprecated. Use 'rmax' instead.", DeprecationWarning)
if 'in_units' in kwargs:
rho_units = kwargs.pop('in_units')
logger.warning("The 'in_units' keyword is deprecated. Use 'rho_units' instead.", DeprecationWarning)
if center:
trans = halo.center(sim, mode='ssc')
else:
trans = transformation.NullTransformation(sim)
with trans:
ps = profile.Profile(sim, ndim=3, type=bin_spacing, nbins=nbins, rmin =rmin, rmax=rmax)
r = ps['rbins']
den = ps['density']
if r_units is not None:
r = r.in_units(r_units)
if rho_units is not None:
den = den.in_units(rho_units)
plt.errorbar(r, den, yerr=den / np.sqrt(ps['n']), fmt='o', **kwargs)
plt.yscale('log')
plt.xscale('log')
plt.xlabel('$r / '+r.units.latex()+'$')
plt.ylabel(r'$\rho / '+den.units.latex()+'$')