コード例 #1
0
    def __init__(self, *args, **kwargs):
        """
        NAME:
           __init__
        PURPOSE:
           initialize an actionAngleIsochrone object
        INPUT:
           Either:

              b= scale parameter of the isochrone parameter (can be Quantity)

              ip= instance of a IsochronePotential

           ro= distance from vantage point to GC (kpc; can be Quantity)

           vo= circular velocity at ro (km/s; can be Quantity)

        OUTPUT:
        
           instance

        HISTORY:
           2013-09-08 - Written - Bovy (IAS)
        """
        actionAngle.__init__(self,
                             ro=kwargs.get('ro', None),
                             vo=kwargs.get('vo', None))
        if not 'b' in kwargs and not 'ip' in kwargs:  #pragma: no cover
            raise IOError("Must specify b= for actionAngleIsochrone")
        if 'ip' in kwargs:
            ip = kwargs['ip']
            if not isinstance(ip, IsochronePotential):  #pragma: no cover
                raise IOError(
                    "'Provided ip= does not appear to be an instance of an IsochronePotential"
                )
            # Check the units
            self._pot = ip
            self._check_consistent_units()
            self.b = ip.b
            self.amp = ip._amp
        else:
            self.b = kwargs['b']
            if _APY_LOADED and isinstance(self.b, units.Quantity):
                self.b = self.b.to(units.kpc).value / self._ro
            rb = nu.sqrt(self.b**2. + 1.)
            self.amp = (self.b + rb)**2. * rb
        self._c = False
        ext_loaded = False
        if ext_loaded and (('c' in kwargs and kwargs['c'])
                           or not 'c' in kwargs):  #pragma: no cover
            self._c = True
        else:
            self._c = False
        if not self._c:
            self._ip = IsochronePotential(amp=self.amp, b=self.b)
        #Define _pot, because some functions that use actionAngle instances need this
        self._pot = IsochronePotential(amp=self.amp, b=self.b)
        # Check the units
        self._check_consistent_units()
        return None
コード例 #2
0
ファイル: test_qdf.py プロジェクト: danielmckeown/galpy
def test_setup_diffsetups():
    #Test the different ways to setup a qdf object
    #Test errors
    try:
        qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1.,
                               aA=aAS,cutcounter=True)
    except IOError: pass
    else: raise AssertionError("qdf setup w/o pot set did not raise exception")
    try:
        qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1.,
                               pot=MWPotential,cutcounter=True)
    except IOError: pass
    else: raise AssertionError("qdf setup w/o aA set did not raise exception")
    from galpy.potential import LogarithmicHaloPotential
    try:
        qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1.,
                               pot=LogarithmicHaloPotential(),
                               aA=aAS,cutcounter=True)
    except IOError: pass
    else: raise AssertionError("qdf setup w/ aA potential different from pot= did not raise exception")
    #qdf setup with an actionAngleIsochrone instance (issue #190)
    from galpy.potential import IsochronePotential
    from galpy.actionAngle import actionAngleIsochrone
    ip= IsochronePotential(normalize=1.,b=2.)
    try:
        qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1.,
                               pot=ip,
                               aA=actionAngleIsochrone(ip=ip),cutcounter=True)
    except:
        raise
        raise AssertionError('quasi-isothermaldf setup w/ an actionAngleIsochrone instance failed')
    #qdf setup with an actionAngleIsochrone instance should raise error if potentials are not the same
    ip= IsochronePotential(normalize=1.,b=2.)
    try:
        qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1.,
                               pot=ip,
                               aA=actionAngleIsochrone(ip=IsochronePotential(normalize=1.,b=2.5)),
                               cutcounter=True)
    except IOError: pass
    else: raise AssertionError("qdf setup w/ aA potential different from pot= did not raise exception")
    #precompute
    qdf= quasiisothermaldf(1./4.,0.2,0.1,1.,1.,
                           pot=MWPotential,aA=aAS,cutcounter=True,
                           _precomputerg=True)
    qdfnpc= quasiisothermaldf(1./4.,0.2,0.1,1.,1.,
                              pot=MWPotential,aA=aAS,cutcounter=True,
                              _precomputerg=False)
    assert numpy.fabs(qdf.rg(1.1)-qdfnpc.rg(1.1)) < 10.**-5., 'rg calculated from qdf instance w/ precomputerg set is not the same as that computed from an instance w/o it set'
コード例 #3
0
def test_actionAngleTorus_Isochrone_actions():
    from galpy.potential import IsochronePotential
    from galpy.actionAngle import actionAngleTorus, \
        actionAngleIsochrone
    ip = IsochronePotential(normalize=1., b=1.2)
    aAI = actionAngleIsochrone(ip=ip)
    tol = -6.
    aAT = actionAngleTorus(pot=ip, tol=tol)
    jr, jphi, jz = 0.075, 1.1, 0.05
    angler = numpy.array([0.])
    anglephi = numpy.array([numpy.pi])
    anglez = numpy.array([numpy.pi / 2.])
    # Calculate position from aAT
    RvR = aAT(jr, jphi, jz, angler, anglephi, anglez).T
    # Calculate actions from aAI
    ji = aAI(*RvR)
    djr = numpy.fabs((ji[0] - jr) / jr)
    dlz = numpy.fabs((ji[1] - jphi) / jphi)
    djz = numpy.fabs((ji[2] - jz) / jz)
    assert djr < 10.**tol, 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for Jr at %f%%' % (
        djr * 100.)
    assert dlz < 10.**tol, 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for Jr at %f%%' % (
        dlz * 100.)
    assert djz < 10.**tol, 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for Jr at %f%%' % (
        djz * 100.)
    return None
コード例 #4
0
def test_adinvariance():
    from galpy.potential import IsochronePotential
    from galpy.orbit import Orbit
    from galpy.actionAngle import actionAngleIsochrone
    # Initialize two different IsochronePotentials
    ip1= IsochronePotential(normalize=1.,b=1.)
    ip2= IsochronePotential(normalize=0.5,b=1.)
    # Use TimeInterpPotential to interpolate smoothly
    tip= TimeInterpPotential(ip1,ip2,dt=100.,tform=50.)
    # Integrate: 1) Orbit in the first isochrone potential
    o1= Orbit([1.,0.1,1.1,0.0,0.1,0.])
    ts= numpy.linspace(0.,50.,1001)
    o1.integrate(ts,tip)
    o1.plot(d1='x',d2='y',xrange=[-1.6,1.6],yrange=[-1.6,1.6],
            color='b')
    # 2) Orbit in the transition
    o2= o1(ts[-1]) # Last time step => initial time step
    ts2= numpy.linspace(50.,150.,1001)
    o2.integrate(ts2,tip)
    o2.plot(d1='x',d2='y',overplot=True,color='g')
    # 3) Orbit in the second isochrone potential
    o3= o2(ts2[-1])
    ts3= numpy.linspace(150.,200.,1001)
    o3.integrate(ts3,tip)
    o3.plot(d1='x',d2='y',overplot=True,color='r')
    # Now we calculate energy, maximum height, and mean radius
    print(o1.E(pot=ip1), (o1.rperi()+o1.rap())/2, o1.zmax())
    assert numpy.fabs(o1.E(pot=ip1)+2.79921356237) < 10.**-4., 'Energy in the adiabatic invariance test is different'
    assert numpy.fabs((o1.rperi()+o1.rap())/2-1.07854158141) < 10.**-4., 'mean radius in the adiabatic invariance test is different'
    assert numpy.fabs(o1.zmax()-0.106331362938) < 10.**-4., 'zmax in the adiabatic invariance test is different'
    print(o3.E(pot=ip2), (o3.rperi()+o3.rap())/2, o3.zmax())
    assert numpy.fabs(o3.E(pot=ip2)+1.19677002624) < 10.**-4., 'Energy in the adiabatic invariance test is different'
    assert numpy.fabs((o3.rperi()+o3.rap())/2-1.39962036137) < 10.**-4., 'mean radius in the adiabatic invariance test is different'
    assert numpy.fabs(o3.zmax()-0.138364269321) < 10.**-4., 'zmax in the adiabatic invariance test is different'
    # The orbit has clearly moved to larger radii,
    # the actions are however conserved from beginning to end
    aAI1= actionAngleIsochrone(ip=ip1); print(aAI1(o1))
    js= aAI1(o1)
    assert numpy.fabs(js[0]-numpy.array([ 0.00773779])) < 10.**-4., 'action in the adiabatic invariance test is different'
    assert numpy.fabs(js[1]-numpy.array([ 1.1])) < 10.**-4., 'action in the adiabatic invariance test is different'
    assert numpy.fabs(js[2]-numpy.array([ 0.0045361])) < 10.**-4., 'action in the adiabatic invariance test is different'
    aAI2= actionAngleIsochrone(ip=ip2); print(aAI2(o3))  
    js= aAI2(o3)
    assert numpy.fabs(js[0]-numpy.array([ 0.00773812])) < 10.**-4., 'action in the adiabatic invariance test is different'
    assert numpy.fabs(js[1]-numpy.array([ 1.1])) < 10.**-4., 'action in the adiabatic invariance test is different'
    assert numpy.fabs(js[2]-numpy.array([ 0.0045361])) < 10.**-4., 'action in the adiabatic invariance test is different'
    return None
コード例 #5
0
def test_actionAngleTorus_Isochrone_freqsAngles():
    from galpy.potential import IsochronePotential
    from galpy.actionAngle import actionAngleTorus, \
        actionAngleIsochrone
    ip = IsochronePotential(normalize=1., b=1.2)
    aAI = actionAngleIsochrone(ip=ip)
    tol = -6.
    aAT = actionAngleTorus(pot=ip, tol=tol)
    jr, jphi, jz = 0.075, 1.1, 0.05
    angler = numpy.array([0.1]) + numpy.linspace(0., numpy.pi, 101)
    angler = angler % (2. * numpy.pi)
    anglephi = numpy.array([numpy.pi]) + numpy.linspace(0., numpy.pi, 101)
    anglephi = anglephi % (2. * numpy.pi)
    anglez = numpy.array([numpy.pi / 2.]) + numpy.linspace(0., numpy.pi, 101)
    anglez = anglez % (2. * numpy.pi)
    # Calculate position from aAT
    RvRom = aAT.xvFreqs(jr, jphi, jz, angler, anglephi, anglez)
    # Calculate actions, frequencies, and angles from aAI
    ws = aAI.actionsFreqsAngles(*RvRom[0].T)
    dOr = numpy.fabs((ws[3] - RvRom[1]))
    dOp = numpy.fabs((ws[4] - RvRom[2]))
    dOz = numpy.fabs((ws[5] - RvRom[3]))
    dar = numpy.fabs((ws[6] - angler))
    dap = numpy.fabs((ws[7] - anglephi))
    daz = numpy.fabs((ws[8] - anglez))
    dar[dar > numpy.pi] -= 2. * numpy.pi
    dar[dar < -numpy.pi] += 2. * numpy.pi
    dap[dap > numpy.pi] -= 2. * numpy.pi
    dap[dap < -numpy.pi] += 2. * numpy.pi
    daz[daz > numpy.pi] -= 2. * numpy.pi
    daz[daz < -numpy.pi] += 2. * numpy.pi
    assert numpy.all(
        dOr < 10.**tol
    ), 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for Or at %f%%' % (
        numpy.nanmax(dOr) * 100.)
    assert numpy.all(
        dOp < 10.**tol
    ), 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for Ophi at %f%%' % (
        numpy.nanmax(dOp) * 100.)
    assert numpy.all(
        dOz < 10.**tol
    ), 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for Oz at %f%%' % (
        numpy.nanmax(dOz) * 100.)
    assert numpy.all(
        dar < 10.**tol
    ), 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for ar at %f' % (
        numpy.nanmax(dar))
    assert numpy.all(
        dap < 10.**tol
    ), 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for aphi at %f' % (
        numpy.nanmax(dap))
    assert numpy.all(
        daz < 10.**tol
    ), 'actionAngleTorus and actionAngleIsochrone applied to isochrone potential disagree for az at %f' % (
        numpy.nanmax(daz))
    return None
コード例 #6
0
    def __init__(self,*args,**kwargs):
        """
        NAME:
           __init__
        PURPOSE:
           initialize an actionAngleIsochrone object
        INPUT:
           Either:

              b= scale parameter of the isochrone parameter

              ip= instance of a IsochronePotential
        OUTPUT:
        HISTORY:
           2013-09-08 - Written - Bovy (IAS)
        """
        if not 'b' in kwargs and not 'ip' in kwargs: #pragma: no cover
            raise IOError("Must specify b= for actionAngleIsochrone")
        if 'ip' in kwargs:
            ip= kwargs['ip']
            if not isinstance(ip,IsochronePotential): #pragma: no cover
                raise IOError("'Provided ip= does not appear to be an instance of an IsochronePotential")
            self.b= ip.b
            self.amp= ip._amp
        else:
            self.b= kwargs['b']
            rb= nu.sqrt(self.b**2.+1.)
            self.amp= (self.b+rb)**2.*rb
        self._c= False
        ext_loaded= False
        if ext_loaded and (('c' in kwargs and kwargs['c'])
                           or not 'c' in kwargs): #pragma: no cover
            self._c= True
        else:
            self._c= False
        if not self._c:
            self._ip= IsochronePotential(amp=self.amp,b=self.b)
        #Define _pot, because some functions that use actionAngle instances need this
        self._pot= IsochronePotential(amp=self.amp,b=self.b)
        return None
コード例 #7
0
    def __init__(self,*args,**kwargs):
        """
        NAME:
           __init__
        PURPOSE:
           initialize an actionAngleIsochroneApprox object
        INPUT:

           Either:

              b= scale parameter of the isochrone parameter

              ip= instance of a IsochronePotential

              aAI= instance of an actionAngleIsochrone

           pot= potential to calculate action-angle variables for

           tintJ= (default: 100) time to integrate orbits for to estimate actions

           ntintJ= (default: 10000) number of time-integration points

           integrate_method= (default: 'dopr54_c') integration method to use

        OUTPUT:
        HISTORY:
           2013-09-10 - Written - Bovy (IAS)
        """
        if not 'pot' in kwargs: #pragma: no cover
            raise IOError("Must specify pot= for actionAngleIsochroneApprox")
        self._pot= kwargs['pot']
        if self._pot == MWPotential:
            warnings.warn("Use of MWPotential as a Milky-Way-like potential is deprecated; galpy.potential.MWPotential2014, a potential fit to a large variety of dynamical constraints (see Bovy 2015), is the preferred Milky-Way-like potential in galpy",
                          galpyWarning)
        if not 'b' in kwargs and not 'ip' in kwargs \
                and not 'aAI' in kwargs: #pragma: no cover
            raise IOError("Must specify b=, ip=, or aAI= for actionAngleIsochroneApprox")
        if 'aAI' in kwargs:
            if not isinstance(kwargs['aAI'],actionAngleIsochrone): #pragma: no cover
                raise IOError("'Provided aAI= does not appear to be an instance of an actionAngleIsochrone")
            self._aAI= kwargs['aAI']
        elif 'ip' in kwargs:
            ip= kwargs['ip']
            if not isinstance(ip,IsochronePotential): #pragma: no cover
                raise IOError("'Provided ip= does not appear to be an instance of an IsochronePotential")
            self._aAI= actionAngleIsochrone(ip=ip)
        else:
            self._aAI= actionAngleIsochrone(ip=IsochronePotential(b=kwargs['b'],
                                                                  normalize=1.))
        self._tintJ= kwargs.get('tintJ',100.)
        self._ntintJ= kwargs.get('ntintJ',10000)
        self._tsJ= nu.linspace(0.,self._tintJ,self._ntintJ)
        self._integrate_method= kwargs.get('integrate_method','dopr54_c')
        self._c= False
        ext_loaded= False
        if ext_loaded and (('c' in kwargs and kwargs['c'])
                           or not 'c' in kwargs): #pragma: no cover
            self._c= True
        else:
            self._c= False
        return None
コード例 #8
0
    def __init__(self,*args,**kwargs):
        """
        NAME:
           __init__
        PURPOSE:
           initialize an actionAngleIsochroneApprox object
        INPUT:

           Either:

              b= scale parameter of the isochrone parameter (can be Quantity)

              ip= instance of a IsochronePotential

              aAI= instance of an actionAngleIsochrone

           pot= potential to calculate action-angle variables for

           tintJ= (default: 100) time to integrate orbits for to estimate actions (can be Quantity)

           ntintJ= (default: 10000) number of time-integration points

           integrate_method= (default: 'dopr54_c') integration method to use

           dt= (None) orbit.integrate dt keyword (for fixed stepsize integration)

           maxn= (default: 3) Default value for all methods when using a grid in vec(n) up to this n (zero-based)

           ro= distance from vantage point to GC (kpc; can be Quantity)

           vo= circular velocity at ro (km/s; can be Quantity)

        OUTPUT:

           instance

        HISTORY:
           2013-09-10 - Written - Bovy (IAS)
        """
        actionAngle.__init__(self,
                             ro=kwargs.get('ro',None),vo=kwargs.get('vo',None))
        if not 'pot' in kwargs: #pragma: no cover
            raise IOError("Must specify pot= for actionAngleIsochroneApprox")
        self._pot= flatten_potential(kwargs['pot'])
        if self._pot == MWPotential:
            warnings.warn("Use of MWPotential as a Milky-Way-like potential is deprecated; galpy.potential.MWPotential2014, a potential fit to a large variety of dynamical constraints (see Bovy 2015), is the preferred Milky-Way-like potential in galpy",
                          galpyWarning)
        if not 'b' in kwargs and not 'ip' in kwargs \
                and not 'aAI' in kwargs: #pragma: no cover
            raise IOError("Must specify b=, ip=, or aAI= for actionAngleIsochroneApprox")
        if 'aAI' in kwargs:
            if not isinstance(kwargs['aAI'],actionAngleIsochrone): #pragma: no cover
                raise IOError("'Provided aAI= does not appear to be an instance of an actionAngleIsochrone")
            self._aAI= kwargs['aAI']
        elif 'ip' in kwargs:
            ip= kwargs['ip']
            if not isinstance(ip,IsochronePotential): #pragma: no cover
                raise IOError("'Provided ip= does not appear to be an instance of an IsochronePotential")
            self._aAI= actionAngleIsochrone(ip=ip)
        else:
            if _APY_LOADED and isinstance(kwargs['b'],units.Quantity):
                b= kwargs['b'].to(units.kpc).value/self._ro
            else:
                b= kwargs['b']
            self._aAI= actionAngleIsochrone(ip=IsochronePotential(b=b,
                                                                  normalize=1.))
        self._tintJ= kwargs.get('tintJ',100.)
        if _APY_LOADED and isinstance(self._tintJ,units.Quantity):
            self._tintJ= self._tintJ.to(units.Gyr).value\
                /time_in_Gyr(self._vo,self._ro)
        self._ntintJ= kwargs.get('ntintJ',10000)
        self._integrate_dt= kwargs.get('dt',None)
        self._tsJ= nu.linspace(0.,self._tintJ,self._ntintJ)
        self._integrate_method= kwargs.get('integrate_method','dopr54_c')
        self._maxn= kwargs.get('maxn',3)
        self._c= False
        ext_loaded= False
        if ext_loaded and (('c' in kwargs and kwargs['c'])
                           or not 'c' in kwargs): #pragma: no cover
            self._c= True
        else:
            self._c= False
        # Check the units
        self._check_consistent_units()
        return None
def create_frames(basefilename):
    """Create Frames.

    Parameters
    ----------
    basefilename : str

    Returns
    -------
    None

    """
    pot = IsochronePotential(normalize=1.0, b=1.2)
    aAT = actionAngleIsochrone(ip=pot)
    bmock = 0.8
    aAF = actionAngleIsochrone(b=bmock)

    o = Orbit([1.0, 0.3, 0.9, 0.2, 1.0, 0.1])
    tfac, skip = 10, 1
    ndesired = 30 * 25
    times = numpy.linspace(0.0, 7.0, tfac * ndesired) * u.Gyr

    # Subsample
    otimesIndices = (numpy.arange(len(times)) /
                     float(len(times) - 1))**10 * (len(times) - 2)
    otimesIndices = numpy.unique(numpy.floor(otimesIndices).astype("int"))
    if len(otimesIndices) > ndesired:
        sfac = int(numpy.floor(len(otimesIndices) / float(ndesired)))
        otimesIndices = otimesIndices[::sfac]
    otimes = times[otimesIndices]
    o.integrate(times, pot)

    # Compute all actions in the wrong potential
    acfs = aAF.actionsFreqsAngles(
        o.R(times),
        o.vR(times),
        o.vT(times),
        o.z(times),
        o.vz(times),
        o.phi(times),
    )
    js = (acfs[0], acfs[1], acfs[2])
    danglerI = ((numpy.roll(acfs[6], -1) - acfs[6]) % (2.0 * numpy.pi))[:-1]
    jrC = numpy.cumsum(acfs[0][:-1] * danglerI) / numpy.cumsum(danglerI)

    # And also the actions in the true potential
    jsT = aAT(o.R(times), o.vR(times), o.vT(times), o.z(times), o.vz(times))
    jrT = numpy.median(jsT[0]) * _RO * _VO

    # ---------------------------------------------------------------
    # Plotting

    # Setup gridspec
    gs = gridspec.GridSpec(1, 3, wspace=0.325, bottom=0.2, left=0.075)

    # For each time step, plot: orbit, Jr, <Jr>
    for ii in tqdm(range(len(otimes))):
        bovy_plot.bovy_print(
            fig_width=11.2,
            fig_height=4.0,
            axes_labelsize=17.0,
            text_fontsize=12.0,
            xtick_labelsize=13.0,
            ytick_labelsize=13.0,
        )
        pyplot.figure()
        pyplot.subplot(gs[0])
        minIndx = otimesIndices[ii] - 100

        if minIndx < 0:
            minIndx = 0
        bovy_plot.bovy_plot(
            [o.x(otimes[ii:ii + 1]) * _RO],
            [o.z(otimes[ii:ii + 1]) * _RO],
            "o",
            ms=15.0,
            gcf=True,
            xrange=[-19.0, 19.0],
            yrange=[-19.0, 19.0],
            xlabel=r"$X\,(\mathrm{kpc})$",
            ylabel=r"$z\,(\mathrm{kpc})$",
        )

        if ii > 0:
            bovy_plot.bovy_plot(
                o.x(times[minIndx:otimesIndices[ii]:skip]) * _RO,
                o.z(times[minIndx:otimesIndices[ii]:skip]) * _RO,
                "-",
                overplot=True,
            )

        pyplot.subplot(gs[1])
        bovy_plot.bovy_plot(
            [times[otimesIndices[ii]].value],
            [js[0][otimesIndices[ii]] * _RO * _VO],
            "o",
            ms=15.0,
            gcf=True,
            xrange=[0.0, 1.0 + times[otimesIndices[ii]].value],
            yrange=[0.0, 349.0],
            xlabel=r"$\mathrm{time}\,(\mathrm{Gyr})$",
            ylabel=r"$J_R\,(\mathrm{kpc\,km\,s}^{-1})$",
        )

        if ii > 0:
            bovy_plot.bovy_plot(
                times[:otimesIndices[ii]:skip].value,
                js[0][:otimesIndices[ii]:skip] * _RO * _VO,
                "-",
                overplot=True,
            )

        pyplot.axhline(jrT, ls="--", color="k")
        pyplot.subplot(gs[2])
        bovy_plot.bovy_plot(
            [otimes[ii].value],
            [jrC[otimesIndices[ii]] * _RO * _VO],
            "o",
            ms=15.0,
            gcf=True,
            xrange=[0.0, 1.0 + times[otimesIndices[ii]].value],
            yrange=[
                (otimes[ii] / times[-1])**0.3 * (jrT - 3),
                349.0 + (otimes[ii] / times[-1])**0.3 * (jrT + 3 - 349.0),
            ],
            xlabel=r"$\mathrm{time}\,(\mathrm{Gyr})$",
            ylabel=r"$J_R\,(\mathrm{kpc\,km\,s}^{-1})$",
        )

        if ii > 0:
            bovy_plot.bovy_plot(
                times[:otimesIndices[ii]:skip].value,
                jrC[:otimesIndices[ii]:skip] * _RO * _VO,
                "-",
                overplot=True,
            )

        pyplot.axhline(jrT, ls="--", color="k")
        bovy_plot.bovy_end_print(basefilename + "_%05d.png" % ii)

    return None