[yt-svn] commit/yt: 40 new changesets

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Thu May 8 16:56:04 PDT 2014


40 new commits in yt:

https://bitbucket.org/yt_analysis/yt/commits/dd02c584126f/
Changeset:   dd02c584126f
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-24 23:57:20
Summary:     First try at getting WCS coordinates on PlotWindow plots.
Affected #:  9 files

diff -r cc91caeca992b1113627555a54e0e8bf92a87082 -r dd02c584126fd887b2cb06479572a7fd8d4e30ed yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -275,6 +275,7 @@
         self._initfinished = False
         self._axes_unit_names = None
         self.center = None
+        self._wcs_axes = False
         self._periodic = periodic
         self.oblique = oblique
         self.buff_size = buff_size
@@ -621,6 +622,23 @@
         self._axes_unit_names = unit_name
         return self
 
+    @invalidate_data
+    @invalidate_plot
+    def set_wcs_axes(self, set_axes, wcs=None):
+        from wcsaxes import WCSAxes
+        if set_axes:
+            self._wcs_axes = True
+            for f in self.plots:
+                rect = self.plots[f]._get_best_layout()[1]
+                fig = self.plots[f].figure
+                ax = WCSAxes(fig, rect, wcs=wcs, frameon=False)
+                ax.set_xlabel("RA")
+                ax.set_ylabel("Dec")
+                fig.add_axes(ax)
+        else:
+            if not self._wcs_axes: return
+            self._wcs_axes = False
+
 class PWViewerMPL(PlotWindow):
     """Viewer using matplotlib as a backend via the WindowPlotMPL.
 
@@ -753,52 +771,60 @@
                 self.figure_size, fp.get_size(),
                 aspect, fig, axes, cax)
 
-            axes_unit_labels = ['', '']
-            comoving = False
-            hinv = False
-            for i, un in enumerate((unit_x, unit_y)):
-                # Use sympy to factor h out of the unit.  In this context 'un'
-                # is a string, so we call the Unit constructor.
-                expr = Unit(un, registry=self.pf.unit_registry).expr
-                h_expr = Unit('h', registry=self.pf.unit_registry).expr
-                # See http://docs.sympy.org/latest/modules/core.html#sympy.core.expr.Expr
-                h_power = expr.as_coeff_exponent(h_expr)[1]
-                # un is now the original unit, but with h factored out.
-                un = str(expr*h_expr**(-1*h_power))
-                if str(un).endswith('cm') and un != 'cm':
-                    comoving = True
-                    un = un[:-2]
-                # no length units besides code_length end in h so this is safe
-                if h_power == -1:
-                    hinv = True
-                elif h_power != 0:
-                    # It doesn't make sense to scale a position by anything
-                    # other than h**-1
-                    raise RuntimeError
-                if un in formatted_length_unit_names:
-                    un = formatted_length_unit_names[un]
-                if un not in ['1', 'u', 'unitary']:
-                    if hinv:
-                        un = un + '\,h^{-1}'
-                    if comoving:
-                        un = un + '\,(1+z)^{-1}'
-                    axes_unit_labels[i] = '\/\/('+un+')'
+            if not self._wcs_axes:
+                axes_unit_labels = ['', '']
+                comoving = False
+                hinv = False
+                for i, un in enumerate((unit_x, unit_y)):
+                    # Use sympy to factor h out of the unit.  In this context 'un'
+                    # is a string, so we call the Unit constructor.
+                    expr = Unit(un, registry=self.pf.unit_registry).expr
+                    h_expr = Unit('h', registry=self.pf.unit_registry).expr
+                    # See http://docs.sympy.org/latest/modules/core.html#sympy.core.expr.Expr
+                    h_power = expr.as_coeff_exponent(h_expr)[1]
+                    # un is now the original unit, but with h factored out.
+                    un = str(expr*h_expr**(-1*h_power))
+                    if str(un).endswith('cm') and un != 'cm':
+                        comoving = True
+                        un = un[:-2]
+                    # no length units besides code_length end in h so this is safe
+                    if h_power == -1:
+                        hinv = True
+                    elif h_power != 0:
+                        # It doesn't make sense to scale a position by anything
+                        # other than h**-1
+                        raise RuntimeError
+                    if un in formatted_length_unit_names:
+                        un = formatted_length_unit_names[un]
+                    if un not in ['1', 'u', 'unitary']:
+                        if hinv:
+                            un = un + '\,h^{-1}'
+                        if comoving:
+                            un = un + '\,(1+z)^{-1}'
+                        axes_unit_labels[i] = '\/\/('+un+')'
 
-            if self.oblique:
-                labels = [r'$\rm{Image\/x'+axes_unit_labels[0]+'}$',
-                          r'$\rm{Image\/y'+axes_unit_labels[1]+'}$']
+                if self.oblique:
+                    labels = [r'$\rm{Image\/x'+axes_unit_labels[0]+'}$',
+                              r'$\rm{Image\/y'+axes_unit_labels[1]+'}$']
+                else:
+                    labels = [r'$\rm{'+axis_labels[axis_index][i]+
+                              axes_unit_labels[i] + r'}$' for i in (0,1)]
+
+                self.plots[f].axes.set_xlabel(labels[0],fontproperties=fp)
+                self.plots[f].axes.set_ylabel(labels[1],fontproperties=fp)
+
+                for label in (self.plots[f].axes.get_xticklabels() +
+                              self.plots[f].axes.get_yticklabels() +
+                              [self.plots[f].axes.xaxis.get_offset_text(),
+                               self.plots[f].axes.yaxis.get_offset_text()]):
+                    label.set_fontproperties(fp)
+
             else:
-                labels = [r'$\rm{'+axis_labels[axis_index][i]+
-                          axes_unit_labels[i] + r'}$' for i in (0,1)]
-
-            self.plots[f].axes.set_xlabel(labels[0],fontproperties=fp)
-            self.plots[f].axes.set_ylabel(labels[1],fontproperties=fp)
-
-            for label in (self.plots[f].axes.get_xticklabels() +
-                          self.plots[f].axes.get_yticklabels() +
-                          [self.plots[f].axes.xaxis.get_offset_text(),
-                           self.plots[f].axes.yaxis.get_offset_text()]):
-                label.set_fontproperties(fp)
+                wcs_axes = self.plots[f].figure.axes[-1]
+                self.plots[f].axes.set_xticklabels([])
+                self.plots[f].axes.set_yticklabels([])
+                wcs_axes.set_xlim(self.xlim[0].value, self.xlim[1].value)
+                wcs_axes.set_ylim(self.ylim[0].value, self.ylim[1].value)
 
             colorbar_label = image.info['label']
 


https://bitbucket.org/yt_analysis/yt/commits/50ddf8f84e38/
Changeset:   50ddf8f84e38
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-25 14:40:34
Summary:     Making significant progress on this
Affected #:  9 files

diff -r dd02c584126fd887b2cb06479572a7fd8d4e30ed -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 yt/analysis_modules/halo_analysis/halo_finding_methods.py
--- a/yt/analysis_modules/halo_analysis/halo_finding_methods.py
+++ /dev/null
@@ -1,132 +0,0 @@
-"""
-Halo Finding methods
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-
-from yt.analysis_modules.halo_finding.halo_objects import \
-    FOFHaloFinder, HOPHaloFinder
-from yt.frontends.halo_catalogs.halo_catalog.data_structures import \
-    HaloCatalogDataset
-from yt.frontends.stream.data_structures import \
-    load_particles
-
-from .operator_registry import \
-    finding_method_registry
-
-def add_finding_method(name, function):
-    finding_method_registry[name] = HaloFindingMethod(function)
-    
-class HaloFindingMethod(object):
-    r"""
-    A halo finding method is a callback that performs halo finding on a 
-    dataset and returns a new dataset that is the loaded halo finder output.
-    """
-    def __init__(self, function, args=None, kwargs=None):
-        self.function = function
-        self.args = args
-        if self.args is None: self.args = []
-        self.kwargs = kwargs
-        if self.kwargs is None: self.kwargs = {}
-
-    def __call__(self, ds):
-        return self.function(ds, *self.args, **self.kwargs)
-
-def _hop_method(pf):
-    r"""
-    Run the Hop halo finding method.
-    """
-    
-    halo_list = HOPHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("hop", _hop_method)
-
-def _fof_method(pf):
-    r"""
-    Run the FoF halo finding method.
-    """
-
-    halo_list = FOFHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("fof", _fof_method)
-
-def _rockstar_method(pf):
-    r"""
-    Run the Rockstar halo finding method.
-    """
-
-    from yt.frontends.halo_catalogs.rockstar.data_structures import \
-     RockstarDataset
-    from yt.analysis_modules.halo_finding.rockstar.api import \
-     RockstarHaloFinder
-    
-    rh = RockstarHaloFinder(pf)
-    rh.run()
-    halos_pf = RockstarDataset("rockstar_halos/halos_0.0.bin")
-    halos_pf.create_field_info()
-    return halos_pf
-add_finding_method("rockstar", _rockstar_method)
-
-def _parse_old_halo_list(data_pf, halo_list):
-    r"""
-    Convert the halo list into a loaded dataset.
-    """
-
-    num_halos = len(halo_list)
-
-    # Set up fields that we want to pull from identified halos and their units
-    new_fields = ['particle_identifier', 'particle_mass', 'particle_position_x', 
-        'particle_position_y','particle_position_z',
-        'virial_radius']
-    new_units = [ '', 'g', 'cm', 'cm','cm','cm']
-
-    # Set up a dictionary based on those fields 
-    # with empty arrays where we will fill in their values
-    halo_properties = { f : (np.zeros(num_halos),unit) \
-        for f, unit in zip(new_fields,new_units)}
-
-    # Iterate through the halos pulling out their positions and virial quantities
-    # and filling in the properties dictionary
-    for i,halo in enumerate(halo_list):
-        halo_properties['particle_identifier'][0][i] = i
-        halo_properties['particle_mass'][0][i] = halo.virial_mass().in_cgs()
-        halo_properties['virial_radius'][0][i] = halo.virial_radius().in_cgs()
-
-        com = halo.center_of_mass().in_cgs()
-        halo_properties['particle_position_x'][0][i] = com[0]
-        halo_properties['particle_position_y'][0][i] = com[1]
-        halo_properties['particle_position_z'][0][i] = com[2]
-
-    # Define a bounding box based on original data pf
-    bbox = np.array([data_pf.domain_left_edge.in_cgs(),
-            data_pf.domain_right_edge.in_cgs()]).T
-
-    # Create a pf with the halos as particles
-    particle_pf = load_particles(halo_properties, 
-            bbox=bbox, length_unit = 1, mass_unit=1)
-
-    # Create the field info dictionary so we can reference those fields
-    particle_pf.create_field_info()
-
-    for attr in ["current_redshift", "current_time",
-                 "domain_dimensions",
-                 "cosmological_simulation", "omega_lambda",
-                 "omega_matter", "hubble_constant"]:
-        attr_val = getattr(data_pf, attr)
-        setattr(particle_pf, attr, attr_val)
-    particle_pf.current_time = particle_pf.current_time.in_cgs()
-    
-    return particle_pf

diff -r dd02c584126fd887b2cb06479572a7fd8d4e30ed -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r dd02c584126fd887b2cb06479572a7fd8d4e30ed -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r dd02c584126fd887b2cb06479572a7fd8d4e30ed -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r dd02c584126fd887b2cb06479572a7fd8d4e30ed -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 yt/frontends/fits/setup.py
--- a/yt/frontends/fits/setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('fits', parent_package, top_path)
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r dd02c584126fd887b2cb06479572a7fd8d4e30ed -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 yt/frontends/fits/tests/test_outputs.py
--- a/yt/frontends/fits/tests/test_outputs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-FITS frontend tests
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from yt.testing import *
-from yt.utilities.answer_testing.framework import \
-    requires_pf, \
-    small_patch_amr, \
-    big_patch_amr, \
-    data_dir_load
-
-_fields = ("intensity")
-
-m33 = "fits/m33_hi.fits"
- at requires_pf(m33, big_data=True)
-def test_m33():
-    pf = data_dir_load(m33)
-    yield assert_equal, str(pf), "m33_hi.fits"
-    for test in small_patch_amr(m33, _fields):
-        test_m33.__name__ = test.description
-        yield test
-
-_fields = ("x-velocity","y-velocity","z-velocity")
-
-vf = "fits/velocity_field_20.fits"
- at requires_pf(vf)
-def test_velocity_field():
-    pf = data_dir_load(bf)
-    yield assert_equal, str(pf), "velocity_field_20.fits"
-    for test in small_patch_amr(vf, _fields):
-        test_velocity_field.__name__ = test.description
-        yield test

diff -r dd02c584126fd887b2cb06479572a7fd8d4e30ed -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -624,20 +624,27 @@
 
     @invalidate_data
     @invalidate_plot
-    def set_wcs_axes(self, set_axes, wcs=None):
+    def set_wcs_axes(self, set_axes):
         from wcsaxes import WCSAxes
-        if set_axes:
+        if self.oblique:
+            raise NotImplementedError("WCS axes are not implemented for oblique plots.")
+        if not hasattr(self.pf, "wcs"):
+            raise NotImplementedError("WCS axes are not implemented for this dataset")
+        if set_axes and not self._wcs_axes:
             self._wcs_axes = True
             for f in self.plots:
                 rect = self.plots[f]._get_best_layout()[1]
                 fig = self.plots[f].figure
-                ax = WCSAxes(fig, rect, wcs=wcs, frameon=False)
-                ax.set_xlabel("RA")
-                ax.set_ylabel("Dec")
+                ax = WCSAxes(fig, rect, wcs=self.pf.wcs, frameon=False)
                 fig.add_axes(ax)
         else:
             if not self._wcs_axes: return
             self._wcs_axes = False
+            for f in self.plots:
+                self.plots[f].figure = None
+                self.plots[f].axes = None
+                self.plots[f].cax = None
+            self._setup_plots()
 
 class PWViewerMPL(PlotWindow):
     """Viewer using matplotlib as a backend via the WindowPlotMPL.
@@ -820,11 +827,23 @@
                     label.set_fontproperties(fp)
 
             else:
+
+                axis = self.data_source.axis
                 wcs_axes = self.plots[f].figure.axes[-1]
-                self.plots[f].axes.set_xticklabels([])
-                self.plots[f].axes.set_yticklabels([])
+                wcs = wcs_axes.wcs.wcs
+                #self.plots[f].axes.set_xticklabels([])
+                #self.plots[f].axes.set_yticklabels([])
+                self.plots[f].axes.get_xaxis().set_visible(False)
+                self.plots[f].axes.get_yaxis().set_visible(False)
+
+                wcs_axes.coords[0].set_axislabel(wcs.ctype[x_dict[axis]].split("-")[0],
+                                                 fontproperties=fp)
+                wcs_axes.coords[1].set_axislabel(wcs.ctype[y_dict[axis]].split("-")[0],
+                                                 fontproperties=fp)
                 wcs_axes.set_xlim(self.xlim[0].value, self.xlim[1].value)
                 wcs_axes.set_ylim(self.ylim[0].value, self.ylim[1].value)
+                wcs_axes.coords[0].ticklabels.set_fontproperties(fp)
+                wcs_axes.coords[1].ticklabels.set_fontproperties(fp)
 
             colorbar_label = image.info['label']
 


https://bitbucket.org/yt_analysis/yt/commits/bfa962d39f56/
Changeset:   bfa962d39f56
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-25 14:57:54
Summary:     This mostly works, but need to enforce that it happens along the right axis
Affected #:  9 files

diff -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 -r bfa962d39f566a6f6d2a5177001323d1b11d20fd yt/analysis_modules/halo_analysis/halo_finding_methods.py
--- a/yt/analysis_modules/halo_analysis/halo_finding_methods.py
+++ /dev/null
@@ -1,132 +0,0 @@
-"""
-Halo Finding methods
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-
-from yt.analysis_modules.halo_finding.halo_objects import \
-    FOFHaloFinder, HOPHaloFinder
-from yt.frontends.halo_catalogs.halo_catalog.data_structures import \
-    HaloCatalogDataset
-from yt.frontends.stream.data_structures import \
-    load_particles
-
-from .operator_registry import \
-    finding_method_registry
-
-def add_finding_method(name, function):
-    finding_method_registry[name] = HaloFindingMethod(function)
-    
-class HaloFindingMethod(object):
-    r"""
-    A halo finding method is a callback that performs halo finding on a 
-    dataset and returns a new dataset that is the loaded halo finder output.
-    """
-    def __init__(self, function, args=None, kwargs=None):
-        self.function = function
-        self.args = args
-        if self.args is None: self.args = []
-        self.kwargs = kwargs
-        if self.kwargs is None: self.kwargs = {}
-
-    def __call__(self, ds):
-        return self.function(ds, *self.args, **self.kwargs)
-
-def _hop_method(pf):
-    r"""
-    Run the Hop halo finding method.
-    """
-    
-    halo_list = HOPHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("hop", _hop_method)
-
-def _fof_method(pf):
-    r"""
-    Run the FoF halo finding method.
-    """
-
-    halo_list = FOFHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("fof", _fof_method)
-
-def _rockstar_method(pf):
-    r"""
-    Run the Rockstar halo finding method.
-    """
-
-    from yt.frontends.halo_catalogs.rockstar.data_structures import \
-     RockstarDataset
-    from yt.analysis_modules.halo_finding.rockstar.api import \
-     RockstarHaloFinder
-    
-    rh = RockstarHaloFinder(pf)
-    rh.run()
-    halos_pf = RockstarDataset("rockstar_halos/halos_0.0.bin")
-    halos_pf.create_field_info()
-    return halos_pf
-add_finding_method("rockstar", _rockstar_method)
-
-def _parse_old_halo_list(data_pf, halo_list):
-    r"""
-    Convert the halo list into a loaded dataset.
-    """
-
-    num_halos = len(halo_list)
-
-    # Set up fields that we want to pull from identified halos and their units
-    new_fields = ['particle_identifier', 'particle_mass', 'particle_position_x', 
-        'particle_position_y','particle_position_z',
-        'virial_radius']
-    new_units = [ '', 'g', 'cm', 'cm','cm','cm']
-
-    # Set up a dictionary based on those fields 
-    # with empty arrays where we will fill in their values
-    halo_properties = { f : (np.zeros(num_halos),unit) \
-        for f, unit in zip(new_fields,new_units)}
-
-    # Iterate through the halos pulling out their positions and virial quantities
-    # and filling in the properties dictionary
-    for i,halo in enumerate(halo_list):
-        halo_properties['particle_identifier'][0][i] = i
-        halo_properties['particle_mass'][0][i] = halo.virial_mass().in_cgs()
-        halo_properties['virial_radius'][0][i] = halo.virial_radius().in_cgs()
-
-        com = halo.center_of_mass().in_cgs()
-        halo_properties['particle_position_x'][0][i] = com[0]
-        halo_properties['particle_position_y'][0][i] = com[1]
-        halo_properties['particle_position_z'][0][i] = com[2]
-
-    # Define a bounding box based on original data pf
-    bbox = np.array([data_pf.domain_left_edge.in_cgs(),
-            data_pf.domain_right_edge.in_cgs()]).T
-
-    # Create a pf with the halos as particles
-    particle_pf = load_particles(halo_properties, 
-            bbox=bbox, length_unit = 1, mass_unit=1)
-
-    # Create the field info dictionary so we can reference those fields
-    particle_pf.create_field_info()
-
-    for attr in ["current_redshift", "current_time",
-                 "domain_dimensions",
-                 "cosmological_simulation", "omega_lambda",
-                 "omega_matter", "hubble_constant"]:
-        attr_val = getattr(data_pf, attr)
-        setattr(particle_pf, attr, attr_val)
-    particle_pf.current_time = particle_pf.current_time.in_cgs()
-    
-    return particle_pf

diff -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 -r bfa962d39f566a6f6d2a5177001323d1b11d20fd yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 -r bfa962d39f566a6f6d2a5177001323d1b11d20fd yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 -r bfa962d39f566a6f6d2a5177001323d1b11d20fd yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 -r bfa962d39f566a6f6d2a5177001323d1b11d20fd yt/frontends/fits/setup.py
--- a/yt/frontends/fits/setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('fits', parent_package, top_path)
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 -r bfa962d39f566a6f6d2a5177001323d1b11d20fd yt/frontends/fits/tests/test_outputs.py
--- a/yt/frontends/fits/tests/test_outputs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-FITS frontend tests
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from yt.testing import *
-from yt.utilities.answer_testing.framework import \
-    requires_pf, \
-    small_patch_amr, \
-    big_patch_amr, \
-    data_dir_load
-
-_fields = ("intensity")
-
-m33 = "fits/m33_hi.fits"
- at requires_pf(m33, big_data=True)
-def test_m33():
-    pf = data_dir_load(m33)
-    yield assert_equal, str(pf), "m33_hi.fits"
-    for test in small_patch_amr(m33, _fields):
-        test_m33.__name__ = test.description
-        yield test
-
-_fields = ("x-velocity","y-velocity","z-velocity")
-
-vf = "fits/velocity_field_20.fits"
- at requires_pf(vf)
-def test_velocity_field():
-    pf = data_dir_load(bf)
-    yield assert_equal, str(pf), "velocity_field_20.fits"
-    for test in small_patch_amr(vf, _fields):
-        test_velocity_field.__name__ = test.description
-        yield test

diff -r 50ddf8f84e38cdaa0fa497ef76a03cec10ff47e2 -r bfa962d39f566a6f6d2a5177001323d1b11d20fd yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -628,14 +628,14 @@
         from wcsaxes import WCSAxes
         if self.oblique:
             raise NotImplementedError("WCS axes are not implemented for oblique plots.")
-        if not hasattr(self.pf, "wcs"):
+        if not hasattr(self.pf, "wcs_2d"):
             raise NotImplementedError("WCS axes are not implemented for this dataset")
         if set_axes and not self._wcs_axes:
             self._wcs_axes = True
             for f in self.plots:
                 rect = self.plots[f]._get_best_layout()[1]
                 fig = self.plots[f].figure
-                ax = WCSAxes(fig, rect, wcs=self.pf.wcs, frameon=False)
+                ax = WCSAxes(fig, rect, wcs=self.pf.wcs_2d, frameon=False)
                 fig.add_axes(ax)
         else:
             if not self._wcs_axes: return
@@ -831,15 +831,12 @@
                 axis = self.data_source.axis
                 wcs_axes = self.plots[f].figure.axes[-1]
                 wcs = wcs_axes.wcs.wcs
-                #self.plots[f].axes.set_xticklabels([])
-                #self.plots[f].axes.set_yticklabels([])
                 self.plots[f].axes.get_xaxis().set_visible(False)
                 self.plots[f].axes.get_yaxis().set_visible(False)
-
-                wcs_axes.coords[0].set_axislabel(wcs.ctype[x_dict[axis]].split("-")[0],
-                                                 fontproperties=fp)
-                wcs_axes.coords[1].set_axislabel(wcs.ctype[y_dict[axis]].split("-")[0],
-                                                 fontproperties=fp)
+                xlabel = wcs.ctype[x_dict[axis]].split("-")[0]
+                ylabel = wcs.ctype[y_dict[axis]].split("-")[0]
+                wcs_axes.coords[0].set_axislabel(xlabel, fontproperties=fp)
+                wcs_axes.coords[1].set_axislabel(ylabel, fontproperties=fp)
                 wcs_axes.set_xlim(self.xlim[0].value, self.xlim[1].value)
                 wcs_axes.set_ylim(self.ylim[0].value, self.ylim[1].value)
                 wcs_axes.coords[0].ticklabels.set_fontproperties(fp)


https://bitbucket.org/yt_analysis/yt/commits/40ec067a0f76/
Changeset:   40ec067a0f76
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-25 15:10:21
Summary:     Merge
Affected #:  42 files

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f doc/source/reference/api/api.rst
--- a/doc/source/reference/api/api.rst
+++ b/doc/source/reference/api/api.rst
@@ -660,7 +660,6 @@
    ~yt.utilities.parallel_tools.parallel_analysis_interface.parallel_passthrough
    ~yt.utilities.parallel_tools.parallel_analysis_interface.parallel_root_only
    ~yt.utilities.parallel_tools.parallel_analysis_interface.parallel_simple_proxy
-   ~yt.utilities.parallel_tools.parallel_analysis_interface.parallel_splitter
 
 Math Utilities
 --------------

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/analysis_modules/halo_finding/rockstar/rockstar_groupies.pyx
--- a/yt/analysis_modules/halo_finding/rockstar/rockstar_groupies.pyx
+++ b/yt/analysis_modules/halo_finding/rockstar/rockstar_groupies.pyx
@@ -220,12 +220,11 @@
         cdef np.int64_t last_fof_tag = 1
         cdef np.int64_t k = 0
         for i in range(num_particles):
-            if fof_tags[i] == 0:
+            if fof_tags[i] < 0:
                 continue
             if fof_tags[i] != last_fof_tag:
                 last_fof_tag = fof_tags[i]
                 if k > 16:
-                    print "Finding subs", k, i
                     fof_obj.num_p = k
                     find_subs(&fof_obj)
                 k = 0

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -53,6 +53,7 @@
     answer_testing_bitwise = 'False',
     gold_standard_filename = 'gold311',
     local_standard_filename = 'local001',
+    answer_tests_url = 'http://answers.yt-project.org/%s_%s',
     sketchfab_api_key = 'None',
     thread_field_detection = 'False',
     ignore_invalid_unit_operation_errors = 'False'

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -379,9 +379,9 @@
 
     def count_particles(self, selector, x, y, z):
         # We don't cache the selector results
-        count = selector.count_points(x,y,z)
+        count = selector.count_points(x,y,z, 0.0)
         return count
 
     def select_particles(self, selector, x, y, z):
-        mask = selector.select_points(x,y,z)
+        mask = selector.select_points(x,y,z, 0.0)
         return mask

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -249,11 +249,11 @@
 
     def count_particles(self, selector, x, y, z):
         # We don't cache the selector results
-        count = selector.count_points(x,y,z)
+        count = selector.count_points(x,y,z, 0.0)
         return count
 
     def select_particles(self, selector, x, y, z):
-        mask = selector.select_points(x,y,z)
+        mask = selector.select_points(x,y,z, 0.0)
         return mask
 
 class ParticleOctreeSubset(OctreeSubset):

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -575,6 +575,8 @@
         self.unit_registry.add("code_magnetic", 1.0, dimensions.magnetic_field)
         self.unit_registry.add("code_temperature", 1.0, dimensions.temperature)
         self.unit_registry.add("code_velocity", 1.0, dimensions.velocity)
+        self.unit_registry.add("code_metallicity", 1.0,
+                               dimensions.dimensionless)
 
     def set_units(self):
         """
@@ -629,12 +631,10 @@
                     self.length_unit / self.time_unit)
         self.unit_registry.modify("code_velocity", vel_unit)
         # domain_width does not yet exist
-        if self.domain_left_edge is None or self.domain_right_edge is None:
-            DW = np.zeros(3)
-        else:
+        if None not in (self.domain_left_edge, self.domain_right_edge):
             DW = self.arr(self.domain_right_edge - self.domain_left_edge, "code_length")
-        self.unit_registry.add("unitary", float(DW.max() * DW.units.cgs_value),
-                               DW.units.dimensions)
+            self.unit_registry.add("unitary", float(DW.max() * DW.units.cgs_value),
+                                   DW.units.dimensions)
 
     _arr = None
     @property

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/data_objects/unstructured_mesh.py
--- a/yt/data_objects/unstructured_mesh.py
+++ b/yt/data_objects/unstructured_mesh.py
@@ -171,9 +171,9 @@
 
     def count_particles(self, selector, x, y, z):
         # We don't cache the selector results
-        count = selector.count_points(x,y,z)
+        count = selector.count_points(x,y,z, 0.0)
         return count
 
     def select_particles(self, selector, x, y, z):
-        mask = selector.select_points(x,y,z)
+        mask = selector.select_points(x,y,z, 0.0)
         return mask

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/art/io.py
--- a/yt/frontends/art/io.py
+++ b/yt/frontends/art/io.py
@@ -74,7 +74,7 @@
         pbool, idxa, idxb = _determine_field_size(pf, ftype, self.ls, ptmax)
         pstr = 'particle_position_%s'
         x,y,z = [self._get_field((ftype, pstr % ax)) for ax in 'xyz']
-        mask = selector.select_points(x, y, z)
+        mask = selector.select_points(x, y, z, 0.0)
         if self.caching:
             self.masks[key] = mask
             return self.masks[key]

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/artio/io.py
--- a/yt/frontends/artio/io.py
+++ b/yt/frontends/artio/io.py
@@ -64,7 +64,7 @@
                 for ptype, field_list in sorted(ptf.items()):
                     x, y, z = (np.asarray(rv[ptype][pn % ax], dtype="=f8")
                                for ax in 'XYZ')
-                    mask = selector.select_points(x, y, z)
+                    mask = selector.select_points(x, y, z, 0.0)
                     if mask is None: continue
                     for field in field_list:
                         data = np.asarray(rv[ptype][field], "=f8")

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/enzo/io.py
--- a/yt/frontends/enzo/io.py
+++ b/yt/frontends/enzo/io.py
@@ -104,7 +104,7 @@
                             r"particle_position_%s")
                     x, y, z = (np.asarray(pds.get(pn % ax).value, dtype="=f8")
                                for ax in 'xyz')
-                    mask = selector.select_points(x, y, z)
+                    mask = selector.select_points(x, y, z, 0.0)
                     if mask is None: continue
                     for field in field_list:
                         data = np.asarray(pds.get(field).value, "=f8")

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -78,7 +78,6 @@
 
 ap = astropy_imports()
 
-known_units = dict([(unit.lower(),unit) for unit in default_unit_symbol_lut])
 lat_prefixes = ["DEC","GLAT"]
 lon_prefixes = ["RA","GLON"]
 vel_prefixes = ["V","ENER","FREQ","WAV"]
@@ -125,7 +124,7 @@
                 return v
         return None
 
-    def _determine_image_units(self, header):
+    def _determine_image_units(self, header, known_units):
         try:
             field_units = header["bunit"].lower().strip(" ").replace(" ", "")
             # FITS units always return upper-case, so we need to get
@@ -171,6 +170,7 @@
         self._file_map = {}
         self._ext_map = {}
         self._scale_map = {}
+        known_units = dict([(unit.lower(),unit) for unit in self.pf.unit_registry.lut])
         # We create a field from each slice on the 4th axis
         if self.parameter_file.naxis == 4:
             naxis4 = self.parameter_file.primary_header["naxis4"]
@@ -180,7 +180,7 @@
             for j, hdu in enumerate(fits_file):
                 if self._ensure_same_dims(hdu):
                     for k in xrange(naxis4):
-                        units = self._determine_image_units(hdu.header)
+                        units = self._determine_image_units(hdu.header, known_units)
                         try:
                             # Grab field name from btype
                             fname = hdu.header["btype"].lower()
@@ -249,12 +249,13 @@
             self.grid_right_edge[0,:] = pf.domain_right_edge
             self.grid_dimensions[0] = pf.domain_dimensions
 
-        try:
-            self.grid_particle_count[:] = pf.primary_header["naxis2"]
-        except KeyError:
-            self.grid_particle_count[:] = 0.0
-        self._particle_indices = np.zeros(self.num_grids + 1, dtype='int64')
-        self._particle_indices[1] = self.grid_particle_count.squeeze()
+        if self.pf.events_data:
+            try:
+                self.grid_particle_count[:] = pf.primary_header["naxis2"]
+            except KeyError:
+                self.grid_particle_count[:] = 0.0
+            self._particle_indices = np.zeros(self.num_grids + 1, dtype='int64')
+            self._particle_indices[1] = self.grid_particle_count.squeeze()
 
         self.grid_levels.flat[:] = 0
         self.grids = np.empty(self.num_grids, dtype='object')

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/flash/io.py
--- a/yt/frontends/flash/io.py
+++ b/yt/frontends/flash/io.py
@@ -93,7 +93,7 @@
                 x = np.asarray(p_fields[start:end, px], dtype="=f8")
                 y = np.asarray(p_fields[start:end, py], dtype="=f8")
                 z = np.asarray(p_fields[start:end, pz], dtype="=f8")
-                mask = selector.select_points(x, y, z)
+                mask = selector.select_points(x, y, z, 0.0)
                 if mask is None: continue
                 for field in field_list:
                     fi = self._particle_fields[field]

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/halo_catalogs/halo_catalog/io.py
--- a/yt/frontends/halo_catalogs/halo_catalog/io.py
+++ b/yt/frontends/halo_catalogs/halo_catalog/io.py
@@ -68,7 +68,7 @@
                     x = f['particle_position_x'].value.astype("float64")
                     y = f['particle_position_y'].value.astype("float64")
                     z = f['particle_position_z'].value.astype("float64")
-                    mask = selector.select_points(x, y, z)
+                    mask = selector.select_points(x, y, z, 0.0)
                     del x, y, z
                     if mask is None: continue
                     for field in field_list:

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/halo_catalogs/rockstar/io.py
--- a/yt/frontends/halo_catalogs/rockstar/io.py
+++ b/yt/frontends/halo_catalogs/rockstar/io.py
@@ -74,7 +74,7 @@
                     x = halos['particle_position_x'].astype("float64")
                     y = halos['particle_position_y'].astype("float64")
                     z = halos['particle_position_z'].astype("float64")
-                    mask = selector.select_points(x, y, z)
+                    mask = selector.select_points(x, y, z, 0.0)
                     del x, y, z
                     if mask is None: continue
                     for field in field_list:

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/ramses/io.py
--- a/yt/frontends/ramses/io.py
+++ b/yt/frontends/ramses/io.py
@@ -77,7 +77,7 @@
                 for ptype, field_list in sorted(ptf.items()):
                     x, y, z = (np.asarray(rv[ptype, pn % ax], "=f8")
                                for ax in 'xyz')
-                    mask = selector.select_points(x, y, z)
+                    mask = selector.select_points(x, y, z, 0.0)
                     for field in field_list:
                         data = np.asarray(rv.pop((ptype, field))[mask], "=f8")
                         yield (ptype, field), data

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/sph/data_structures.py
--- a/yt/frontends/sph/data_structures.py
+++ b/yt/frontends/sph/data_structures.py
@@ -471,16 +471,20 @@
         self.current_time = hvals["time"]
         nz = 1 << self.over_refine_factor
         self.domain_dimensions = np.ones(3, "int32") * nz
-        if self.parameters.get('bPeriodic', True):
-            self.periodicity = (True, True, True)
+        periodic = self.parameters.get('bPeriodic', True)
+        period = self.parameters.get('dPeriod', None)
+        comoving = self.parameters.get('bComove', False)
+        self.periodicity = (periodic, periodic, periodic)
+        if comoving and period is None:
+            period = 1.0
+        if periodic and period is not None:
             # If we are periodic, that sets our domain width to either 1 or dPeriod.
-            self.domain_left_edge = np.zeros(3, "float64") - 0.5*self.parameters.get('dPeriod', 1)
-            self.domain_right_edge = np.zeros(3, "float64") + 0.5*self.parameters.get('dPeriod', 1)
+            self.domain_left_edge = np.zeros(3, "float64") - 0.5*period
+            self.domain_right_edge = np.zeros(3, "float64") + 0.5*period
         else:
-            self.periodicity = (False, False, False)
             self.domain_left_edge = None
             self.domain_right_edge = None
-        if self.parameters.get('bComove', False):
+        if comoving:
             cosm = self._cosmology_parameters or {}
             self.scale_factor = hvals["time"]#In comoving simulations, time stores the scale factor a
             self.cosmological_simulation = 1

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/sph/io.py
--- a/yt/frontends/sph/io.py
+++ b/yt/frontends/sph/io.py
@@ -99,7 +99,7 @@
                 g = f["/%s" % ptype]
                 coords = g["Coordinates"][:].astype("float64")
                 mask = selector.select_points(
-                            coords[:,0], coords[:,1], coords[:,2])
+                            coords[:,0], coords[:,1], coords[:,2], 0.0)
                 del coords
                 if mask is None: continue
                 for field in field_list:
@@ -281,7 +281,7 @@
                 pos = self._read_field_from_file(f,
                             tp[ptype], "Coordinates")
                 mask = selector.select_points(
-                    pos[:,0], pos[:,1], pos[:,2])
+                    pos[:,0], pos[:,1], pos[:,2], 0.0)
                 del pos
                 if mask is None: continue
                 for field in field_list:
@@ -534,7 +534,7 @@
                 mask = selector.select_points(
                     p["Coordinates"]['x'].astype("float64"),
                     p["Coordinates"]['y'].astype("float64"),
-                    p["Coordinates"]['z'].astype("float64"))
+                    p["Coordinates"]['z'].astype("float64"), 0.0)
                 if mask is None: continue
                 tf = self._fill_fields(field_list, p, mask, data_file)
                 for field in field_list:
@@ -557,6 +557,8 @@
             pf.domain_left_edge = 0
             pf.domain_right_edge = 0
             f.seek(pf._header_offset)
+            mi =   np.array([1e30, 1e30, 1e30], dtype="float64")
+            ma =  -np.array([1e30, 1e30, 1e30], dtype="float64")
             for iptype, ptype in enumerate(self._ptypes):
                 # We'll just add the individual types separately
                 count = data_file.total_particles[ptype]
@@ -566,19 +568,23 @@
                     c = min(CHUNKSIZE, stop - ind)
                     pp = np.fromfile(f, dtype = self._pdtypes[ptype],
                                      count = c)
-                    for ax in 'xyz':
-                        mi = pp["Coordinates"][ax].min()
-                        ma = pp["Coordinates"][ax].max()
-                        outlier = self.arr(np.max(np.abs((mi,ma))), 'code_length')
-                        if outlier > pf.domain_right_edge or -outlier < pf.domain_left_edge:
-                            # scale these up so the domain is slightly
-                            # larger than the most distant particle position
-                            pf.domain_left_edge = -1.01*outlier
-                            pf.domain_right_edge = 1.01*outlier
+                    eps = np.finfo(pp["Coordinates"]["x"].dtype).eps
+                    np.minimum(mi, [pp["Coordinates"]["x"].min(),
+                                    pp["Coordinates"]["y"].min(),
+                                    pp["Coordinates"]["z"].min()], mi)
+                    np.maximum(ma, [pp["Coordinates"]["x"].max(),
+                                    pp["Coordinates"]["y"].max(),
+                                    pp["Coordinates"]["z"].max()], ma)
                     ind += c
-        pf.domain_left_edge = np.ones(3)*pf.domain_left_edge
-        pf.domain_right_edge = np.ones(3)*pf.domain_right_edge
-        pf.domain_width = np.ones(3)*2*pf.domain_right_edge
+        # We extend by 1%.
+        DW = ma - mi
+        mi -= 0.01 * DW
+        ma += 0.01 * DW
+        pf.domain_left_edge = pf.arr(mi, 'code_length')
+        pf.domain_right_edge = pf.arr(ma, 'code_length')
+        pf.domain_width = DW = pf.domain_right_edge - pf.domain_left_edge
+        pf.unit_registry.add("unitary", float(DW.max() * DW.units.cgs_value),
+                                 DW.units.dimensions)
 
     def _initialize_index(self, data_file, regions):
         pf = data_file.pf
@@ -745,7 +751,7 @@
                 c = np.frombuffer(s, dtype="float64")
                 c.shape = (c.shape[0]/3.0, 3)
                 mask = selector.select_points(
-                            c[:,0], c[:,1], c[:,2])
+                            c[:,0], c[:,1], c[:,2], 0.0)
                 del c
                 if mask is None: continue
                 for field in field_list:

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/frontends/stream/io.py
--- a/yt/frontends/stream/io.py
+++ b/yt/frontends/stream/io.py
@@ -85,7 +85,7 @@
                 for ptype, field_list in sorted(ptf.items()):
                     x, y, z  = (gf[ptype, "particle_position_%s" % ax]
                                 for ax in 'xyz')
-                    mask = selector.select_points(x, y, z)
+                    mask = selector.select_points(x, y, z, 0.0)
                     if mask is None: continue
                     for field in field_list:
                         data = np.asarray(gf[ptype, field])
@@ -127,7 +127,7 @@
             for ptype, field_list in sorted(ptf.items()):
                 x, y, z = (f[ptype, "particle_position_%s" % ax]
                            for ax in 'xyz')
-                mask = selector.select_points(x, y, z)
+                mask = selector.select_points(x, y, z, 0.0)
                 if mask is None: continue
                 for field in field_list:
                     data = f[ptype, field][mask]

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/geometry/coordinate_handler.py
--- a/yt/geometry/coordinate_handler.py
+++ b/yt/geometry/coordinate_handler.py
@@ -24,7 +24,7 @@
 from yt.utilities.io_handler import io_registry
 from yt.utilities.logger import ytLogger as mylog
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
-    ParallelAnalysisInterface, parallel_splitter
+    ParallelAnalysisInterface
 from yt.utilities.lib.misc_utilities import \
     pixelize_cylinder
 import yt.visualization._MPL as _MPL

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/geometry/geometry_handler.py
--- a/yt/geometry/geometry_handler.py
+++ b/yt/geometry/geometry_handler.py
@@ -36,7 +36,7 @@
 from yt.utilities.io_handler import io_registry
 from yt.utilities.logger import ytLogger as mylog
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
-    ParallelAnalysisInterface, parallel_splitter
+    ParallelAnalysisInterface, parallel_root_only
 from yt.utilities.exceptions import YTFieldNotFound
 
 class Index(ParallelAnalysisInterface):
@@ -126,7 +126,8 @@
         if getattr(self, "io", None) is not None: return
         self.io = io_registry[self.dataset_type](self.parameter_file)
 
-    def _save_data(self, array, node, name, set_attr=None, force=False, passthrough = False):
+    @parallel_root_only
+    def save_data(self, array, node, name, set_attr=None, force=False, passthrough = False):
         """
         Arbitrary numpy data will be saved to the region in the datafile
         described by *node* and *name*.  If data file does not exist, it throws
@@ -157,14 +158,6 @@
         del self._data_file
         self._data_file = h5py.File(self.__data_filename, self._data_mode)
 
-    save_data = parallel_splitter(_save_data, _reload_data_file)
-
-    def _reset_save_data(self,round_robin=False):
-        if round_robin:
-            self.save_data = self._save_data
-        else:
-            self.save_data = parallel_splitter(self._save_data, self._reload_data_file)
-
     def save_object(self, obj, name):
         """
         Save an object (*obj*) to the data_file using the Pickle protocol,

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/geometry/grid_geometry_handler.py
--- a/yt/geometry/grid_geometry_handler.py
+++ b/yt/geometry/grid_geometry_handler.py
@@ -31,7 +31,7 @@
 from yt.utilities.physical_constants import sec_per_year
 from yt.utilities.io_handler import io_registry
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
-    ParallelAnalysisInterface, parallel_splitter
+    ParallelAnalysisInterface
 from yt.utilities.lib.GridTree import GridTree, MatchPointsToGrids
 
 from yt.data_objects.data_containers import data_object_registry

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/geometry/oct_geometry_handler.py
--- a/yt/geometry/oct_geometry_handler.py
+++ b/yt/geometry/oct_geometry_handler.py
@@ -30,7 +30,7 @@
 from yt.utilities.definitions import MAXLEVEL
 from yt.utilities.io_handler import io_registry
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
-    ParallelAnalysisInterface, parallel_splitter
+    ParallelAnalysisInterface
 
 from yt.data_objects.data_containers import data_object_registry
 

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/geometry/particle_geometry_handler.py
--- a/yt/geometry/particle_geometry_handler.py
+++ b/yt/geometry/particle_geometry_handler.py
@@ -32,7 +32,7 @@
 from yt.utilities.definitions import MAXLEVEL
 from yt.utilities.io_handler import io_registry
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
-    ParallelAnalysisInterface, parallel_splitter
+    ParallelAnalysisInterface
 
 from yt.data_objects.data_containers import data_object_registry
 from yt.data_objects.octree_subset import ParticleOctreeSubset

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/geometry/selection_routines.pyx
--- a/yt/geometry/selection_routines.pyx
+++ b/yt/geometry/selection_routines.pyx
@@ -455,10 +455,10 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def count_points(self, np.ndarray[np.float64_t, ndim=1] x,
-                           np.ndarray[np.float64_t, ndim=1] y,
-                           np.ndarray[np.float64_t, ndim=1] z,
-                           np.float64_t radius = 0.0):
+    def count_points(self, np.ndarray[anyfloat, ndim=1] x,
+                           np.ndarray[anyfloat, ndim=1] y,
+                           np.ndarray[anyfloat, ndim=1] z,
+                           np.float64_t radius):
         cdef int count = 0
         cdef int i
         cdef np.float64_t pos[3]
@@ -483,10 +483,10 @@
     @cython.boundscheck(False)
     @cython.wraparound(False)
     @cython.cdivision(True)
-    def select_points(self, np.ndarray[np.float64_t, ndim=1] x,
-                            np.ndarray[np.float64_t, ndim=1] y,
-                            np.ndarray[np.float64_t, ndim=1] z,
-                            np.float64_t radius = 0.0):
+    def select_points(self, np.ndarray[anyfloat, ndim=1] x,
+                            np.ndarray[anyfloat, ndim=1] y,
+                            np.ndarray[anyfloat, ndim=1] z,
+                            np.float64_t radius):
         cdef int count = 0
         cdef int i
         cdef np.float64_t pos[3]

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/units/tests/test_ytarray.py
--- a/yt/units/tests/test_ytarray.py
+++ b/yt/units/tests/test_ytarray.py
@@ -592,3 +592,38 @@
 
     yield assert_array_equal, arr.value, np.array(arr)
     yield assert_array_equal, arr.v, np.array(arr)
+
+
+def test_registry_association():
+    ds = fake_random_pf(64, nprocs=1, length_unit=10)
+    a = ds.quan(3, 'cm')
+    b = YTQuantity(4, 'm')
+    c = ds.quan(6, '')
+    d = 5
+
+    yield assert_equal, id(a.units.registry), id(ds.unit_registry)
+
+    def binary_op_registry_comparison(op):
+        e = op(a, b)
+        f = op(b, a)
+        g = op(c, d)
+        h = op(d, c)
+
+        assert_equal(id(e.units.registry), id(ds.unit_registry))
+        assert_equal(id(f.units.registry), id(b.units.registry))
+        assert_equal(id(g.units.registry), id(h.units.registry))
+        assert_equal(id(g.units.registry), id(ds.unit_registry))
+
+    def unary_op_registry_comparison(op):
+        c = op(a)
+        d = op(b)
+
+        assert_equal(id(c.units.registry), id(ds.unit_registry))
+        assert_equal(id(d.units.registry), id(b.units.registry))
+
+    for op in [operator.add, operator.sub, operator.mul, operator.div,
+               operator.truediv]:
+        yield binary_op_registry_comparison, op
+
+    for op in [operator.abs, operator.neg, operator.pos]:
+        yield unary_op_registry_comparison, op

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -237,7 +237,9 @@
 
     __array_priority__ = 2.0
 
-    def __new__(cls, input_array, input_units=None, registry=None, dtype=np.float64):
+    def __new__(cls, input_array, input_units=None, registry=None, dtype=None):
+        if dtype is None:
+            dtype = getattr(input_array, 'dtype', np.float64)
         if input_array is NotImplemented:
             return input_array
         if registry is None and isinstance(input_units, basestring):
@@ -497,12 +499,16 @@
     def __isub__(self, other):
         """ See __sub__. """
         oth = sanitize_units_add(self, other, "subtraction")
-        return np.subtract(self, other, out=self)
+        return np.subtract(self, oth, out=self)
 
     def __neg__(self):
         """ Negate the data. """
         return YTArray(super(YTArray, self).__neg__())
 
+    def __pos__(self):
+        """ Posify the data. """
+        return YTArray(super(YTArray, self).__pos__(), self.units)
+
     def __mul__(self, right_object):
         """
         Multiply this YTArray by the object on the right of the `*` operator.
@@ -665,7 +671,7 @@
     def __eq__(self, other):
         """ Test if this is equal to the object on the right. """
         # Check that other is a YTArray.
-        if other == None:
+        if other is None:
             # self is a YTArray, so it can't be None.
             return False
         if isinstance(other, YTArray):
@@ -679,7 +685,7 @@
     def __ne__(self, other):
         """ Test if this is not equal to the object on the right. """
         # Check that the other is a YTArray.
-        if other == None:
+        if other is None:
             return True
         if isinstance(other, YTArray):
             if not self.units.same_dimensions_as(other.units):
@@ -763,7 +769,7 @@
                 return ret
         elif context[0] in unary_operators:
             u = getattr(context[1][0], 'units', None)
-            if u == None:
+            if u is None:
                 u = Unit()
             try:
                 unit = self._ufunc_registry[context[0]](u)
@@ -774,10 +780,10 @@
         elif context[0] in binary_operators:
             unit1 = getattr(context[1][0], 'units', None)
             unit2 = getattr(context[1][1], 'units', None)
-            if unit1 == None:
-                unit1 = Unit()
-            if unit2 == None and context[0] is not power:
-                unit2 = Unit()
+            if unit1 is None:
+                unit1 = Unit(registry=getattr(unit2, 'registry', None))
+            if unit2 is None and context[0] is not power:
+                unit2 = Unit(registry=getattr(unit1, 'registry', None))
             elif context[0] is power:
                 unit2 = context[1][1]
                 if isinstance(unit2, np.ndarray):
@@ -817,8 +823,8 @@
         See the documentation for the standard library pickle module:
         http://docs.python.org/2/library/pickle.html
 
-        Unit metadata is encoded in the zeroth element of third element of the 
-        returned tuple, itself a tuple used to restore the state of the ndarray.  
+        Unit metadata is encoded in the zeroth element of third element of the
+        returned tuple, itself a tuple used to restore the state of the ndarray.
         This is always defined for numpy arrays.
         """
         np_ret = super(YTArray, self).__reduce__()

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -45,7 +45,7 @@
 # Set the latest gold and local standard filenames
 _latest = ytcfg.get("yt", "gold_standard_filename")
 _latest_local = ytcfg.get("yt", "local_standard_filename")
-_url_path = "http://yt-answer-tests.s3-website-us-east-1.amazonaws.com/%s_%s"
+_url_path = ytcfg.get("yt", "answer_tests_url")
 
 class AnswerTesting(Plugin):
     name = "answer-testing"
@@ -197,30 +197,20 @@
         if self.answer_name is None: return
         # This is where we dump our result storage up to Amazon, if we are able
         # to.
-        import boto
-        from boto.s3.key import Key
-        c = boto.connect_s3()
-        bucket = c.get_bucket("yt-answer-tests")
-        for pf_name in result_storage:
+        import pyrax
+        pyrax.set_credential_file(os.path.expanduser("~/.yt/rackspace"))
+        cf = pyrax.cloudfiles
+        c = cf.get_container("yt-answer-tests")
+        pb = get_pbar("Storing results ", len(result_storage))
+        for i, pf_name in enumerate(result_storage):
+            pb.update(i)
             rs = cPickle.dumps(result_storage[pf_name])
-            tk = bucket.get_key("%s_%s" % (self.answer_name, pf_name))
-            if tk is not None: tk.delete()
-            k = Key(bucket)
-            k.key = "%s_%s" % (self.answer_name, pf_name)
-
-            pb_widgets = [
-                unicode(k.key, errors='ignore').encode('utf-8'), ' ',
-                progressbar.FileTransferSpeed(),' <<<', progressbar.Bar(),
-                '>>> ', progressbar.Percentage(), ' ', progressbar.ETA()
-                ]
-            self.pbar = progressbar.ProgressBar(widgets=pb_widgets,
-                                                maxval=sys.getsizeof(rs))
-
-            self.pbar.start()
-            k.set_contents_from_string(rs, cb=self.progress_callback,
-                                       num_cb=100000)
-            k.set_acl("public-read")
-            self.pbar.finish()
+            object_name = "%s_%s" % (self.answer_name, pf_name)
+            if object_name in c.get_object_names():
+                obj = c.get_object(object_name)
+                c.delete_object(obj)
+            c.store_object(object_name, rs)
+        pb.finish()
 
 class AnswerTestLocalStorage(AnswerTestStorage):
     def dump(self, result_storage):

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/utilities/io_handler.py
--- a/yt/utilities/io_handler.py
+++ b/yt/utilities/io_handler.py
@@ -146,7 +146,7 @@
             # Here, ptype_map means which particles contribute to a given type.
             # And ptf is the actual fields from disk to read.
             for ptype, (x, y, z) in self._read_particle_coords(chunks, ptf):
-                psize[ptype] += selector.count_points(x, y, z)
+                psize[ptype] += selector.count_points(x, y, z, 0.0)
             self._last_selector_counts = dict(**psize)
             self._last_selector_id = hash(selector)
         # Now we allocate

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/utilities/lib/ContourFinding.pxd
--- a/yt/utilities/lib/ContourFinding.pxd
+++ b/yt/utilities/lib/ContourFinding.pxd
@@ -39,6 +39,7 @@
     ContourID *parent
     ContourID *next
     ContourID *prev
+    np.int64_t count
 
 cdef struct CandidateContour
 

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/utilities/lib/ContourFinding.pyx
--- a/yt/utilities/lib/ContourFinding.pyx
+++ b/yt/utilities/lib/ContourFinding.pyx
@@ -36,6 +36,7 @@
     node.contour_id = contour_id
     node.next = node.parent = NULL
     node.prev = prev
+    node.count = 0
     if prev != NULL: prev.next = node
     return node
 
@@ -631,7 +632,8 @@
                                 np.ndarray[np.float64_t, ndim=2] positions,
                                 np.ndarray[np.int64_t, ndim=1] particle_ids,
                                 int domain_id = -1, int domain_offset = 0,
-                                periodicity = (True, True, True)):
+                                periodicity = (True, True, True),
+                                minimum_count = 8):
         cdef np.ndarray[np.int64_t, ndim=1] pdoms, pcount, pind, doff
         cdef np.float64_t pos[3]
         cdef Oct *oct = NULL, **neighbors = NULL
@@ -728,6 +730,16 @@
                 c1 = container[poffset]
                 c0 = contour_find(c1)
                 contour_ids[pind[poffset]] = c0.contour_id
+                c0.count += 1
+        for i in range(doff.shape[0]):
+            if doff[i] < 0: continue
+            for j in range(pcount[i]):
+                poffset = doff[i] + j
+                c1 = container[poffset]
+                if c1 == NULL: continue
+                c0 = contour_find(c1)
+                if c0.count < minimum_count:
+                    contour_ids[pind[poffset]] = -1
         free(container)
         return contour_ids
 

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/utilities/parallel_tools/parallel_analysis_interface.py
--- a/yt/utilities/parallel_tools/parallel_analysis_interface.py
+++ b/yt/utilities/parallel_tools/parallel_analysis_interface.py
@@ -179,14 +179,13 @@
     used on objects that subclass
     :class:`~yt.utilities.parallel_tools.parallel_analysis_interface.ParallelAnalysisInterface`.
     """
-    if not parallel_capable: return func
     @wraps(func)
     def single_proc_results(self, *args, **kwargs):
         retval = None
         if hasattr(self, "dont_wrap"):
             if func.func_name in self.dont_wrap:
                 return func(self, *args, **kwargs)
-        if self._processing or not self._distributed:
+        if not parallel_capable or self._processing or not self._distributed:
             return func(self, *args, **kwargs)
         comm = _get_comm((self,))
         if self._owner == comm.rank:
@@ -243,6 +242,8 @@
     """
     @wraps(func)
     def barrierize(*args, **kwargs):
+        if not parallel_capable:
+            return func(*args, **kwargs)
         mylog.debug("Entering barrier before %s", func.func_name)
         comm = _get_comm(args)
         comm.barrier()
@@ -250,26 +251,7 @@
         mylog.debug("Entering barrier after %s", func.func_name)
         comm.barrier()
         return retval
-    if parallel_capable:
-        return barrierize
-    else:
-        return func
-
-def parallel_splitter(f1, f2):
-    """
-    This function returns either the function *f1* or *f2* depending on whether
-    or not we're the root processor.  Mainly used in class definitions.
-    """
-    @wraps(f1)
-    def in_order(*args, **kwargs):
-        comm = _get_comm(args)
-        if comm.rank == 0:
-            f1(*args, **kwargs)
-        comm.barrier()
-        if comm.rank != 0:
-            f2(*args, **kwargs)
-    if not parallel_capable: return f1
-    return in_order
+    return barrierize
 
 def parallel_root_only(func):
     """
@@ -278,6 +260,8 @@
     """
     @wraps(func)
     def root_only(*args, **kwargs):
+        if not parallel_capable:
+            return func(*args, **kwargs)
         comm = _get_comm(args)
         rv = None
         if comm.rank == 0:
@@ -292,8 +276,7 @@
         all_clear = comm.mpi_bcast(all_clear)
         if not all_clear: raise RuntimeError
         return rv
-    if parallel_capable: return root_only
-    return func
+    return root_only
 
 class Workgroup(object):
     def __init__(self, size, ranks, comm, name):
@@ -636,6 +619,9 @@
     def __init__(self, comm=None):
         self.comm = comm
         self._distributed = comm is not None and self.comm.size > 1
+
+    def __del__(self):
+        self.comm.Free()
     """
     This is an interface specification providing several useful utility
     functions for analyzing something in parallel.

diff -r bfa962d39f566a6f6d2a5177001323d1b11d20fd -r 40ec067a0f768a218e098c83653c03a91af1466f yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -68,8 +68,8 @@
     from pyparsing import ParseFatalException
 
 def fix_unitary(u):
-    if u is '1':
-        return 'code_length'
+    if u == '1':
+        return 'unitary'
     else:
         return u
 
@@ -380,10 +380,30 @@
 
         Parameters
         ----------
-        deltas : sequence of floats
-            (delta_x, delta_y) in *absolute* code unit coordinates
+        deltas : Two-element sequence of floats, quantities, or (float, unit)
+                 tuples.
+            (delta_x, delta_y).  If a unit is not supplied the unit is assumed
+            to be code_length.
 
         """
+        if len(deltas) != 2:
+            raise RuntimeError(
+                "The pan function accepts a two-element sequence.\n"
+                "Received %s." % (deltas, )
+                )
+        if isinstance(deltas[0], Number) and isinstance(deltas[1], Number):
+            deltas = (self.pf.quan(deltas[0], 'code_length'),
+                      self.pf.quan(deltas[1], 'code_length'))
+        elif isinstance(deltas[0], tuple) and isinstance(deltas[1], tuple):
+            deltas = (self.pf.quan(deltas[0][0], deltas[0][1]),
+                      self.pf.quan(deltas[1][0], deltas[1][1]))
+        elif isinstance(deltas[0], YTQuantity) and isinstance(deltas[1], YTQuantity):
+            pass
+        else:
+            raise RuntimeError(
+                "The arguments of the pan function must be a sequence of floats,\n"
+                "quantities, or (float, unit) tuples. Received %s." % (deltas, )
+                )
         self.xlim = (self.xlim[0] + deltas[0], self.xlim[1] + deltas[0])
         self.ylim = (self.ylim[0] + deltas[1], self.ylim[1] + deltas[1])
         return self


https://bitbucket.org/yt_analysis/yt/commits/bf8a6e80f819/
Changeset:   bf8a6e80f819
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-25 15:20:44
Summary:     Make sure this is only done along the correct axis
Affected #:  9 files

diff -r 40ec067a0f768a218e098c83653c03a91af1466f -r bf8a6e80f81929a02d22fe76061785aec066686b yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -649,7 +649,9 @@
         if self.oblique:
             raise NotImplementedError("WCS axes are not implemented for oblique plots.")
         if not hasattr(self.pf, "wcs_2d"):
-            raise NotImplementedError("WCS axes are not implemented for this dataset")
+            raise NotImplementedError("WCS axes are not implemented for this dataset.")
+        if self.data_source.axis != self.pf.vel_axis:
+            raise NotImplementedError("WCS axes are not implemented for this axis.")
         if set_axes and not self._wcs_axes:
             self._wcs_axes = True
             for f in self.plots:


https://bitbucket.org/yt_analysis/yt/commits/58b003873091/
Changeset:   58b003873091
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-25 15:22:53
Summary:     Return self
Affected #:  9 files

diff -r bf8a6e80f81929a02d22fe76061785aec066686b -r 58b003873091195a0d239aa470cd871469a6d94d yt/analysis_modules/halo_analysis/halo_finding_methods.py
--- a/yt/analysis_modules/halo_analysis/halo_finding_methods.py
+++ /dev/null
@@ -1,132 +0,0 @@
-"""
-Halo Finding methods
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-
-from yt.analysis_modules.halo_finding.halo_objects import \
-    FOFHaloFinder, HOPHaloFinder
-from yt.frontends.halo_catalogs.halo_catalog.data_structures import \
-    HaloCatalogDataset
-from yt.frontends.stream.data_structures import \
-    load_particles
-
-from .operator_registry import \
-    finding_method_registry
-
-def add_finding_method(name, function):
-    finding_method_registry[name] = HaloFindingMethod(function)
-    
-class HaloFindingMethod(object):
-    r"""
-    A halo finding method is a callback that performs halo finding on a 
-    dataset and returns a new dataset that is the loaded halo finder output.
-    """
-    def __init__(self, function, args=None, kwargs=None):
-        self.function = function
-        self.args = args
-        if self.args is None: self.args = []
-        self.kwargs = kwargs
-        if self.kwargs is None: self.kwargs = {}
-
-    def __call__(self, ds):
-        return self.function(ds, *self.args, **self.kwargs)
-
-def _hop_method(pf):
-    r"""
-    Run the Hop halo finding method.
-    """
-    
-    halo_list = HOPHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("hop", _hop_method)
-
-def _fof_method(pf):
-    r"""
-    Run the FoF halo finding method.
-    """
-
-    halo_list = FOFHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("fof", _fof_method)
-
-def _rockstar_method(pf):
-    r"""
-    Run the Rockstar halo finding method.
-    """
-
-    from yt.frontends.halo_catalogs.rockstar.data_structures import \
-     RockstarDataset
-    from yt.analysis_modules.halo_finding.rockstar.api import \
-     RockstarHaloFinder
-    
-    rh = RockstarHaloFinder(pf)
-    rh.run()
-    halos_pf = RockstarDataset("rockstar_halos/halos_0.0.bin")
-    halos_pf.create_field_info()
-    return halos_pf
-add_finding_method("rockstar", _rockstar_method)
-
-def _parse_old_halo_list(data_pf, halo_list):
-    r"""
-    Convert the halo list into a loaded dataset.
-    """
-
-    num_halos = len(halo_list)
-
-    # Set up fields that we want to pull from identified halos and their units
-    new_fields = ['particle_identifier', 'particle_mass', 'particle_position_x', 
-        'particle_position_y','particle_position_z',
-        'virial_radius']
-    new_units = [ '', 'g', 'cm', 'cm','cm','cm']
-
-    # Set up a dictionary based on those fields 
-    # with empty arrays where we will fill in their values
-    halo_properties = { f : (np.zeros(num_halos),unit) \
-        for f, unit in zip(new_fields,new_units)}
-
-    # Iterate through the halos pulling out their positions and virial quantities
-    # and filling in the properties dictionary
-    for i,halo in enumerate(halo_list):
-        halo_properties['particle_identifier'][0][i] = i
-        halo_properties['particle_mass'][0][i] = halo.virial_mass().in_cgs()
-        halo_properties['virial_radius'][0][i] = halo.virial_radius().in_cgs()
-
-        com = halo.center_of_mass().in_cgs()
-        halo_properties['particle_position_x'][0][i] = com[0]
-        halo_properties['particle_position_y'][0][i] = com[1]
-        halo_properties['particle_position_z'][0][i] = com[2]
-
-    # Define a bounding box based on original data pf
-    bbox = np.array([data_pf.domain_left_edge.in_cgs(),
-            data_pf.domain_right_edge.in_cgs()]).T
-
-    # Create a pf with the halos as particles
-    particle_pf = load_particles(halo_properties, 
-            bbox=bbox, length_unit = 1, mass_unit=1)
-
-    # Create the field info dictionary so we can reference those fields
-    particle_pf.create_field_info()
-
-    for attr in ["current_redshift", "current_time",
-                 "domain_dimensions",
-                 "cosmological_simulation", "omega_lambda",
-                 "omega_matter", "hubble_constant"]:
-        attr_val = getattr(data_pf, attr)
-        setattr(particle_pf, attr, attr_val)
-    particle_pf.current_time = particle_pf.current_time.in_cgs()
-    
-    return particle_pf

diff -r bf8a6e80f81929a02d22fe76061785aec066686b -r 58b003873091195a0d239aa470cd871469a6d94d yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r bf8a6e80f81929a02d22fe76061785aec066686b -r 58b003873091195a0d239aa470cd871469a6d94d yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r bf8a6e80f81929a02d22fe76061785aec066686b -r 58b003873091195a0d239aa470cd871469a6d94d yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r bf8a6e80f81929a02d22fe76061785aec066686b -r 58b003873091195a0d239aa470cd871469a6d94d yt/frontends/fits/setup.py
--- a/yt/frontends/fits/setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('fits', parent_package, top_path)
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r bf8a6e80f81929a02d22fe76061785aec066686b -r 58b003873091195a0d239aa470cd871469a6d94d yt/frontends/fits/tests/test_outputs.py
--- a/yt/frontends/fits/tests/test_outputs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-FITS frontend tests
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from yt.testing import *
-from yt.utilities.answer_testing.framework import \
-    requires_pf, \
-    small_patch_amr, \
-    big_patch_amr, \
-    data_dir_load
-
-_fields = ("intensity")
-
-m33 = "fits/m33_hi.fits"
- at requires_pf(m33, big_data=True)
-def test_m33():
-    pf = data_dir_load(m33)
-    yield assert_equal, str(pf), "m33_hi.fits"
-    for test in small_patch_amr(m33, _fields):
-        test_m33.__name__ = test.description
-        yield test
-
-_fields = ("x-velocity","y-velocity","z-velocity")
-
-vf = "fits/velocity_field_20.fits"
- at requires_pf(vf)
-def test_velocity_field():
-    pf = data_dir_load(bf)
-    yield assert_equal, str(pf), "velocity_field_20.fits"
-    for test in small_patch_amr(vf, _fields):
-        test_velocity_field.__name__ = test.description
-        yield test

diff -r bf8a6e80f81929a02d22fe76061785aec066686b -r 58b003873091195a0d239aa470cd871469a6d94d yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -660,14 +660,15 @@
                 ax = WCSAxes(fig, rect, wcs=self.pf.wcs_2d, frameon=False)
                 fig.add_axes(ax)
         else:
-            if not self._wcs_axes: return
+            if not self._wcs_axes: return self
             self._wcs_axes = False
             for f in self.plots:
                 self.plots[f].figure = None
                 self.plots[f].axes = None
                 self.plots[f].cax = None
             self._setup_plots()
-
+        return self
+    
 class PWViewerMPL(PlotWindow):
     """Viewer using matplotlib as a backend via the WindowPlotMPL.
 


https://bitbucket.org/yt_analysis/yt/commits/e2b0a076cd3d/
Changeset:   e2b0a076cd3d
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-25 15:33:57
Summary:     Attempting to fix up the fonts a little bit
Affected #:  9 files

diff -r 58b003873091195a0d239aa470cd871469a6d94d -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 yt/analysis_modules/halo_analysis/halo_finding_methods.py
--- a/yt/analysis_modules/halo_analysis/halo_finding_methods.py
+++ /dev/null
@@ -1,132 +0,0 @@
-"""
-Halo Finding methods
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-
-from yt.analysis_modules.halo_finding.halo_objects import \
-    FOFHaloFinder, HOPHaloFinder
-from yt.frontends.halo_catalogs.halo_catalog.data_structures import \
-    HaloCatalogDataset
-from yt.frontends.stream.data_structures import \
-    load_particles
-
-from .operator_registry import \
-    finding_method_registry
-
-def add_finding_method(name, function):
-    finding_method_registry[name] = HaloFindingMethod(function)
-    
-class HaloFindingMethod(object):
-    r"""
-    A halo finding method is a callback that performs halo finding on a 
-    dataset and returns a new dataset that is the loaded halo finder output.
-    """
-    def __init__(self, function, args=None, kwargs=None):
-        self.function = function
-        self.args = args
-        if self.args is None: self.args = []
-        self.kwargs = kwargs
-        if self.kwargs is None: self.kwargs = {}
-
-    def __call__(self, ds):
-        return self.function(ds, *self.args, **self.kwargs)
-
-def _hop_method(pf):
-    r"""
-    Run the Hop halo finding method.
-    """
-    
-    halo_list = HOPHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("hop", _hop_method)
-
-def _fof_method(pf):
-    r"""
-    Run the FoF halo finding method.
-    """
-
-    halo_list = FOFHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("fof", _fof_method)
-
-def _rockstar_method(pf):
-    r"""
-    Run the Rockstar halo finding method.
-    """
-
-    from yt.frontends.halo_catalogs.rockstar.data_structures import \
-     RockstarDataset
-    from yt.analysis_modules.halo_finding.rockstar.api import \
-     RockstarHaloFinder
-    
-    rh = RockstarHaloFinder(pf)
-    rh.run()
-    halos_pf = RockstarDataset("rockstar_halos/halos_0.0.bin")
-    halos_pf.create_field_info()
-    return halos_pf
-add_finding_method("rockstar", _rockstar_method)
-
-def _parse_old_halo_list(data_pf, halo_list):
-    r"""
-    Convert the halo list into a loaded dataset.
-    """
-
-    num_halos = len(halo_list)
-
-    # Set up fields that we want to pull from identified halos and their units
-    new_fields = ['particle_identifier', 'particle_mass', 'particle_position_x', 
-        'particle_position_y','particle_position_z',
-        'virial_radius']
-    new_units = [ '', 'g', 'cm', 'cm','cm','cm']
-
-    # Set up a dictionary based on those fields 
-    # with empty arrays where we will fill in their values
-    halo_properties = { f : (np.zeros(num_halos),unit) \
-        for f, unit in zip(new_fields,new_units)}
-
-    # Iterate through the halos pulling out their positions and virial quantities
-    # and filling in the properties dictionary
-    for i,halo in enumerate(halo_list):
-        halo_properties['particle_identifier'][0][i] = i
-        halo_properties['particle_mass'][0][i] = halo.virial_mass().in_cgs()
-        halo_properties['virial_radius'][0][i] = halo.virial_radius().in_cgs()
-
-        com = halo.center_of_mass().in_cgs()
-        halo_properties['particle_position_x'][0][i] = com[0]
-        halo_properties['particle_position_y'][0][i] = com[1]
-        halo_properties['particle_position_z'][0][i] = com[2]
-
-    # Define a bounding box based on original data pf
-    bbox = np.array([data_pf.domain_left_edge.in_cgs(),
-            data_pf.domain_right_edge.in_cgs()]).T
-
-    # Create a pf with the halos as particles
-    particle_pf = load_particles(halo_properties, 
-            bbox=bbox, length_unit = 1, mass_unit=1)
-
-    # Create the field info dictionary so we can reference those fields
-    particle_pf.create_field_info()
-
-    for attr in ["current_redshift", "current_time",
-                 "domain_dimensions",
-                 "cosmological_simulation", "omega_lambda",
-                 "omega_matter", "hubble_constant"]:
-        attr_val = getattr(data_pf, attr)
-        setattr(particle_pf, attr, attr_val)
-    particle_pf.current_time = particle_pf.current_time.in_cgs()
-    
-    return particle_pf

diff -r 58b003873091195a0d239aa470cd871469a6d94d -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 58b003873091195a0d239aa470cd871469a6d94d -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r 58b003873091195a0d239aa470cd871469a6d94d -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 58b003873091195a0d239aa470cd871469a6d94d -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 yt/frontends/fits/setup.py
--- a/yt/frontends/fits/setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('fits', parent_package, top_path)
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 58b003873091195a0d239aa470cd871469a6d94d -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 yt/frontends/fits/tests/test_outputs.py
--- a/yt/frontends/fits/tests/test_outputs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-FITS frontend tests
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from yt.testing import *
-from yt.utilities.answer_testing.framework import \
-    requires_pf, \
-    small_patch_amr, \
-    big_patch_amr, \
-    data_dir_load
-
-_fields = ("intensity")
-
-m33 = "fits/m33_hi.fits"
- at requires_pf(m33, big_data=True)
-def test_m33():
-    pf = data_dir_load(m33)
-    yield assert_equal, str(pf), "m33_hi.fits"
-    for test in small_patch_amr(m33, _fields):
-        test_m33.__name__ = test.description
-        yield test
-
-_fields = ("x-velocity","y-velocity","z-velocity")
-
-vf = "fits/velocity_field_20.fits"
- at requires_pf(vf)
-def test_velocity_field():
-    pf = data_dir_load(bf)
-    yield assert_equal, str(pf), "velocity_field_20.fits"
-    for test in small_patch_amr(vf, _fields):
-        test_velocity_field.__name__ = test.description
-        yield test

diff -r 58b003873091195a0d239aa470cd871469a6d94d -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -668,7 +668,7 @@
                 self.plots[f].cax = None
             self._setup_plots()
         return self
-    
+
 class PWViewerMPL(PlotWindow):
     """Viewer using matplotlib as a backend via the WindowPlotMPL.
 
@@ -801,6 +801,9 @@
                 self.figure_size, fp.get_size(),
                 aspect, fig, axes, cax)
 
+            if not hasattr(self.plots[f].figure.axes[-1], "wcs"):
+                self._wcs_axes = False
+
             if not self._wcs_axes:
                 axes_unit_labels = ['', '']
                 comoving = False
@@ -856,14 +859,18 @@
                 wcs = wcs_axes.wcs.wcs
                 self.plots[f].axes.get_xaxis().set_visible(False)
                 self.plots[f].axes.get_yaxis().set_visible(False)
-                xlabel = wcs.ctype[x_dict[axis]].split("-")[0]
-                ylabel = wcs.ctype[y_dict[axis]].split("-")[0]
+                xlabel = "%s (%s)" % (wcs.ctype[x_dict[axis]].split("-")[0],
+                                      wcs.cunit[x_dict[axis]])
+                ylabel = "%s (%s)" % (wcs.ctype[y_dict[axis]].split("-")[0],
+                                      wcs.cunit[x_dict[axis]])
                 wcs_axes.coords[0].set_axislabel(xlabel, fontproperties=fp)
                 wcs_axes.coords[1].set_axislabel(ylabel, fontproperties=fp)
                 wcs_axes.set_xlim(self.xlim[0].value, self.xlim[1].value)
                 wcs_axes.set_ylim(self.ylim[0].value, self.ylim[1].value)
                 wcs_axes.coords[0].ticklabels.set_fontproperties(fp)
                 wcs_axes.coords[1].ticklabels.set_fontproperties(fp)
+                wcs_axes.coords[0].set_major_formatter('d.dd')
+                wcs_axes.coords[1].set_major_formatter('d.dd')
 
             colorbar_label = image.info['label']
 


https://bitbucket.org/yt_analysis/yt/commits/6e4ab9ba5671/
Changeset:   6e4ab9ba5671
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-29 16:03:41
Summary:     Merge
Affected #:  35 files

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 doc/source/examining/loading_data.rst
--- a/doc/source/examining/loading_data.rst
+++ b/doc/source/examining/loading_data.rst
@@ -587,7 +587,15 @@
   keywords, but the resulting field information will necessarily be incomplete.
   For example, field names may not be descriptive, and units will not be
   correct. To get the full use out of yt for FITS files,
-  make sure that the header keywords mentioned above have sensible values.
+  make sure that for each image the following header keywords have sensible values:
+
+  - ``CDELTx``: The pixel width in along axis ``x``
+  - ``CRVALx``: The coordinate value at the reference position along axis ``x``
+  - ``CRPIXx``: The the reference pixel along axis ``x``
+  - ``CTYPEx``: The projection type of axis ``x``
+  - ``CUNITx``: The units of the coordinate along axis ``x``
+  - ``BTYPE``: The type of the image
+  - ``BUNIT``: The units of the image
 
 .. _loading-moab-data:
 

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/analysis_modules/halo_analysis/halo_catalog.py
--- a/yt/analysis_modules/halo_analysis/halo_catalog.py
+++ b/yt/analysis_modules/halo_analysis/halo_catalog.py
@@ -351,6 +351,14 @@
         if self.halos_pf is None:
             # Find the halos and make a dataset of them
             self.halos_pf = self.finder_method(self.data_pf)
+            if self.halos_pf is None:
+                mylog.warning('No halos were found for {0}'.format(\
+                        self.data_pf.basename))
+                if save_catalog:
+                    self.halos_pf = self.data_pf
+                    self.save_catalog()
+                    self.halos_pf = None
+                return
 
             # Assign pf and data sources appropriately
             self.data_source = self.halos_pf.all_data()

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/analysis_modules/halo_analysis/halo_finding_methods.py
--- a/yt/analysis_modules/halo_analysis/halo_finding_methods.py
+++ b/yt/analysis_modules/halo_analysis/halo_finding_methods.py
@@ -25,6 +25,7 @@
 from .operator_registry import \
     finding_method_registry
 
+
 def add_finding_method(name, function):
     finding_method_registry[name] = HaloFindingMethod(function)
     
@@ -75,8 +76,14 @@
     
     rh = RockstarHaloFinder(pf)
     rh.run()
+
+
     halos_pf = RockstarDataset("rockstar_halos/halos_0.0.bin")
-    halos_pf.create_field_info()
+    try:
+        halos_pf.create_field_info()
+    except ValueError:
+        return None
+
     return halos_pf
 add_finding_method("rockstar", _rockstar_method)
 
@@ -87,6 +94,8 @@
 
     num_halos = len(halo_list)
 
+    if num_halos == 0: return None
+
     # Set up fields that we want to pull from identified halos and their units
     new_fields = ['particle_identifier', 'particle_mass', 'particle_position_x', 
         'particle_position_y','particle_position_z',

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/analysis_modules/sunyaev_zeldovich/projection.py
--- a/yt/analysis_modules/sunyaev_zeldovich/projection.py
+++ b/yt/analysis_modules/sunyaev_zeldovich/projection.py
@@ -132,7 +132,7 @@
         --------
         >>> szprj.on_axis("y", center="max", width=(1.0, "Mpc"), source=my_sphere)
         """
-        axis = fix_axis(axis)
+        axis = fix_axis(axis, self.pf)
 
         if center == "c":
             ctr = self.pf.domain_center

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -41,7 +41,6 @@
     march_cubes_grid, march_cubes_grid_flux
 from yt.utilities.data_point_utilities import CombineGrids,\
     DataCubeRefine, DataCubeReplace, FillRegion, FillBuffer
-from yt.utilities.definitions import axis_names, x_dict, y_dict
 from yt.utilities.minimal_representation import \
     MinimalProjectionData
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
@@ -252,8 +251,8 @@
         self._mrep.upload()
 
     def _get_tree(self, nvals):
-        xax = x_dict[self.axis]
-        yax = y_dict[self.axis]
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
         xd = self.pf.domain_dimensions[xax]
         yd = self.pf.domain_dimensions[yax]
         bounds = (self.pf.domain_left_edge[xax],
@@ -292,18 +291,20 @@
         else:
             raise NotImplementedError
         # TODO: Add the combine operation
-        ox = self.pf.domain_left_edge[x_dict[self.axis]]
-        oy = self.pf.domain_left_edge[y_dict[self.axis]]
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
+        ox = self.pf.domain_left_edge[xax]
+        oy = self.pf.domain_left_edge[yax]
         px, py, pdx, pdy, nvals, nwvals = tree.get_all(False, merge_style)
         nvals = self.comm.mpi_allreduce(nvals, op=op)
         nwvals = self.comm.mpi_allreduce(nwvals, op=op)
-        np.multiply(px, self.pf.domain_width[x_dict[self.axis]], px)
+        np.multiply(px, self.pf.domain_width[xax], px)
         np.add(px, ox, px)
-        np.multiply(pdx, self.pf.domain_width[x_dict[self.axis]], pdx)
+        np.multiply(pdx, self.pf.domain_width[xax], pdx)
 
-        np.multiply(py, self.pf.domain_width[y_dict[self.axis]], py)
+        np.multiply(py, self.pf.domain_width[yax], py)
         np.add(py, oy, py)
-        np.multiply(pdy, self.pf.domain_width[y_dict[self.axis]], pdy)
+        np.multiply(pdy, self.pf.domain_width[yax], pdy)
         if self.weight_field is not None:
             np.divide(nvals, nwvals[:,None], nvals)
         # We now convert to half-widths and center-points
@@ -349,8 +350,10 @@
 
     def _initialize_chunk(self, chunk, tree):
         icoords = chunk.icoords
-        i1 = icoords[:,x_dict[self.axis]]
-        i2 = icoords[:,y_dict[self.axis]]
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
+        i1 = icoords[:,xax]
+        i2 = icoords[:,yax]
         ilevel = chunk.ires * self.pf.ires_factor
         tree.initialize_chunk(i1, i2, ilevel)
 
@@ -371,8 +374,10 @@
         else:
             w = np.ones(chunk.ires.size, dtype="float64")
         icoords = chunk.icoords
-        i1 = icoords[:,x_dict[self.axis]]
-        i2 = icoords[:,y_dict[self.axis]]
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
+        i1 = icoords[:,xax]
+        i2 = icoords[:,yax]
         ilevel = chunk.ires * self.pf.ires_factor
         tree.add_chunk_to_tree(i1, i2, ilevel, v, w)
 

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -28,7 +28,6 @@
 from yt.data_objects.particle_io import particle_handler_registry
 from yt.utilities.lib.marching_cubes import \
     march_cubes_grid, march_cubes_grid_flux
-from yt.utilities.definitions import  x_dict, y_dict
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
     ParallelAnalysisInterface
 from yt.utilities.parameter_file_storage import \
@@ -726,9 +725,10 @@
     _spatial = False
     def __init__(self, axis, pf, field_parameters):
         ParallelAnalysisInterface.__init__(self)
-        self.axis = fix_axis(axis)
         super(YTSelectionContainer2D, self).__init__(
             pf, field_parameters)
+        # We need the pf, which will exist by now, for fix_axis.
+        self.axis = fix_axis(axis, self.pf)
         self.set_field_parameter("axis", axis)
 
     def _convert_field_name(self, field):
@@ -821,8 +821,8 @@
         if not iterable(resolution):
             resolution = (resolution, resolution)
         from yt.visualization.fixed_resolution import FixedResolutionBuffer
-        xax = x_dict[self.axis]
-        yax = y_dict[self.axis]
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
         bounds = (center[xax] - width*0.5, center[xax] + width*0.5,
                   center[yax] - height*0.5, center[yax] + height*0.5)
         frb = FixedResolutionBuffer(self, bounds, resolution,

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -20,13 +20,11 @@
 import numpy as np
 
 from yt.funcs import *
-from yt.utilities.definitions import x_dict, y_dict
 
 from yt.data_objects.data_containers import \
     YTFieldData, \
     YTDataContainer, \
     YTSelectionContainer
-from yt.utilities.definitions import x_dict, y_dict
 from yt.fields.field_exceptions import \
     NeedsGridType, \
     NeedsOriginalGrid, \

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/data_objects/selection_data_containers.py
--- a/yt/data_objects/selection_data_containers.py
+++ b/yt/data_objects/selection_data_containers.py
@@ -25,8 +25,6 @@
     YTSelectionContainer1D, YTSelectionContainer2D, YTSelectionContainer3D
 from yt.data_objects.derived_quantities import \
     DerivedQuantityCollection
-from yt.utilities.definitions import \
-    x_dict, y_dict, axis_names
 from yt.utilities.exceptions import YTSphereTooSmall
 from yt.utilities.linear_interpolators import TrilinearFieldInterpolator
 from yt.utilities.minimal_representation import \
@@ -73,12 +71,15 @@
     def __init__(self, axis, coords, pf=None, field_parameters=None):
         super(YTOrthoRayBase, self).__init__(pf, field_parameters)
         self.axis = axis
-        self.px_ax = x_dict[self.axis]
-        self.py_ax = y_dict[self.axis]
-        self.px_dx = 'd%s'%(axis_names[self.px_ax])
-        self.py_dx = 'd%s'%(axis_names[self.py_ax])
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
+        self.px_ax = xax
+        self.py_ax = yax
+        # Even though we may not be using x,y,z we use them here.
+        self.px_dx = 'd%s'%('xyz'[self.px_ax])
+        self.py_dx = 'd%s'%('xyz'[self.py_ax])
         self.px, self.py = coords
-        self.sort_by = axis_names[self.axis]
+        self.sort_by = 'xyz'[self.axis]
 
     @property
     def coords(self):
@@ -191,16 +192,18 @@
         self.coord = coord
 
     def _generate_container_field(self, field):
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
         if self._current_chunk is None:
             self.index._identify_base_chunk(self)
         if field == "px":
-            return self._current_chunk.fcoords[:,x_dict[self.axis]]
+            return self._current_chunk.fcoords[:,xax]
         elif field == "py":
-            return self._current_chunk.fcoords[:,y_dict[self.axis]]
+            return self._current_chunk.fcoords[:,yax]
         elif field == "pdx":
-            return self._current_chunk.fwidth[:,x_dict[self.axis]] * 0.5
+            return self._current_chunk.fwidth[:,xax] * 0.5
         elif field == "pdy":
-            return self._current_chunk.fwidth[:,y_dict[self.axis]] * 0.5
+            return self._current_chunk.fwidth[:,yax] * 0.5
         else:
             raise KeyError(field)
 

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/data_objects/tests/test_chunking.py
--- a/yt/data_objects/tests/test_chunking.py
+++ b/yt/data_objects/tests/test_chunking.py
@@ -3,7 +3,7 @@
 def _get_dobjs(c):
     dobjs = [("sphere", ("center", (1.0, "unitary"))),
              ("sphere", ("center", (0.1, "unitary"))),
-             ("ortho_ray", (0, (c[x_dict[0]], c[y_dict[0]]))),
+             ("ortho_ray", (0, (c[1], c[2]))),
              ("slice", (0, c[0])),
              #("disk", ("center", [0.1, 0.3, 0.6],
              #           (0.2, 'unitary'), (0.1, 'unitary'))),

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/data_objects/tests/test_projection.py
--- a/yt/data_objects/tests/test_projection.py
+++ b/yt/data_objects/tests/test_projection.py
@@ -29,8 +29,8 @@
         uc = [np.unique(c) for c in coords]
         # Some simple projection tests with single grids
         for ax, an in enumerate("xyz"):
-            xax = x_dict[ax]
-            yax = y_dict[ax]
+            xax = pf.coordinates.x_axis[ax]
+            yax = pf.coordinates.y_axis[ax]
             for wf in ["density", None]:
                 fns = []
                 proj = pf.proj(["ones", "density"], ax, weight_field = wf)

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/data_objects/tests/test_slice.py
--- a/yt/data_objects/tests/test_slice.py
+++ b/yt/data_objects/tests/test_slice.py
@@ -17,8 +17,6 @@
 from nose.tools import raises
 from yt.testing import \
     fake_random_pf, assert_equal, assert_array_equal, YTArray
-from yt.utilities.definitions import \
-    x_dict, y_dict
 from yt.utilities.exceptions import \
     YTNoDataInObjectError
 from yt.units.unit_object import Unit
@@ -50,8 +48,8 @@
         slc_pos = 0.5
         # Some simple slice tests with single grids
         for ax, an in enumerate("xyz"):
-            xax = x_dict[ax]
-            yax = y_dict[ax]
+            xax = pf.coordinates.x_axis[ax]
+            yax = pf.coordinates.y_axis[ax]
             for wf in ["density", None]:
                 fns = []
                 slc = pf.slice(ax, slc_pos)

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -170,7 +170,13 @@
         self._file_map = {}
         self._ext_map = {}
         self._scale_map = {}
+        # Since FITS header keywords are case-insensitive, we only pick a subset of
+        # prefixes, ones that we expect to end up in headers.
         known_units = dict([(unit.lower(),unit) for unit in self.pf.unit_registry.lut])
+        for unit in known_units.values():
+            if unit in prefixable_units:
+                for p in ["n","u","m","c","k"]:
+                    known_units[(p+unit).lower()] = p+unit
         # We create a field from each slice on the 4th axis
         if self.parameter_file.naxis == 4:
             naxis4 = self.parameter_file.primary_header["naxis4"]
@@ -179,7 +185,11 @@
         for i, fits_file in enumerate(self.parameter_file._fits_files):
             for j, hdu in enumerate(fits_file):
                 if self._ensure_same_dims(hdu):
-                    for k in xrange(naxis4):
+                    if len(self.pf.override_fields) > 0:
+                        field = self.pf.override_fields.pop(0)
+                        fname = field[0]
+                        units = field[1]
+                    else:
                         units = self._determine_image_units(hdu.header, known_units)
                         try:
                             # Grab field name from btype
@@ -188,17 +198,11 @@
                             # Try to guess the name from the units
                             fname = self._guess_name_from_units(units)
                             # When all else fails
-                            if fname is None:
-                                fname = "image_%d" % (j)
+                            if fname is None: fname = "image_%d" % (j)
+                        if self.pf.num_files > 1: fname += "_file_%d" % (i)
+                    for k in xrange(naxis4):
                         if naxis4 > 1:
                             fname += "_%s_%d" % (hdu.header["CTYPE4"], k+1)
-                        if self.pf.num_files > 1:
-                            try:
-                                fname += "_%5.3f_GHz" % (hdu.header["restfreq"]/1.0e9)
-                            except:
-                                fname += "_%5.3f_GHz" % (hdu.header["restfrq"]/1.0e9)
-                            else:
-                                fname += "_file_%d" % (i)
                         self._axis_map[fname] = k
                         self._file_map[fname] = fits_file
                         self._ext_map[fname] = j
@@ -313,12 +317,17 @@
                  folded_width = None,
                  line_database = None,
                  suppress_astropy_warnings = True,
-                 parameters = None):
+                 parameters = None,
+                 override_fields = None):
 
         if parameters is None:
             parameters = {}
         self.specified_parameters = parameters
 
+        if override_fields is None:
+            override_fields = []
+        self.override_fields = override_fields
+
         self.folded_axis = folded_axis
         self.folded_width = folded_width
         self._unfolded_domain_dimensions = None
@@ -328,6 +337,7 @@
 
         if suppress_astropy_warnings:
             warnings.filterwarnings('ignore', module="astropy", append=True)
+        slave_files = ensure_list(slave_files)
         self.filenames = [filename] + slave_files
         self.num_files = len(self.filenames)
         self.fluid_types += ("fits",)
@@ -345,10 +355,10 @@
         self._fits_files = [self._handle]
         if self.num_files > 1:
             for fits_file in slave_files:
-                self._fits_files.append(ap.pyfits.open(fits_file,
-                                                       memmap=True,
-                                                       do_not_scale_image_data=True,
-                                                       ignore_blank=True))
+                f = ap.pyfits.open(fits_file, memmap=True,
+                                   do_not_scale_image_data=True,
+                                   ignore_blank=True)
+                self._fits_files.append(f)
 
         if len(self._handle) > 1 and self._handle[1].name == "EVENTS":
             self.events_data = True
@@ -358,19 +368,20 @@
             self.wcs = ap.pywcs.WCS(naxis=2)
             self.events_info = {}
             for k,v in self.primary_header.items():
-                if v in ["X","Y"]:
-                    num = k.strip("TTYPE")
-                    self.events_info[v.lower()] = (self.primary_header["TLMIN"+num],
-                                                   self.primary_header["TLMAX"+num],
-                                                   self.primary_header["TCTYP"+num],
-                                                   self.primary_header["TCRVL"+num],
-                                                   self.primary_header["TCDLT"+num],
-                                                   self.primary_header["TCRPX"+num])
-                elif v in ["ENERGY","TIME"]:
-                    num = k.strip("TTYPE")
-                    unit = self.primary_header["TUNIT"+num].lower()
-                    if unit.endswith("ev"): unit = unit.replace("ev","eV")
-                    self.events_info[v.lower()] = unit
+                if k.startswith("TTYP"):
+                    if v.lower() in ["x","y"]:
+                        num = k.strip("TTYPE")
+                        self.events_info[v.lower()] = (self.primary_header["TLMIN"+num],
+                                                       self.primary_header["TLMAX"+num],
+                                                       self.primary_header["TCTYP"+num],
+                                                       self.primary_header["TCRVL"+num],
+                                                       self.primary_header["TCDLT"+num],
+                                                       self.primary_header["TCRPX"+num])
+                    elif v.lower() in ["energy","time"]:
+                        num = k.strip("TTYPE")
+                        unit = self.primary_header["TUNIT"+num].lower()
+                        if unit.endswith("ev"): unit = unit.replace("ev","eV")
+                        self.events_info[v.lower()] = unit
             self.axis_names = [self.events_info[ax][2] for ax in ["x","y"]]
             self.wcs.wcs.cdelt = [self.events_info["x"][4],self.events_info["y"][4]]
             self.wcs.wcs.crpix = [self.events_info["x"][5],self.events_info["y"][5]]
@@ -490,7 +501,7 @@
         if self.nprocs is None:
             self.nprocs = np.around(np.prod(self.domain_dimensions) /
                                     32**self.dimensionality).astype("int")
-            self.nprocs = min(self.nprocs, 512)
+            self.nprocs = max(min(self.nprocs, 512), 1)
 
         # Check to see if this data is in some kind of (Lat,Lon,Vel) format
         self.ppv_data = False
@@ -507,7 +518,8 @@
         if self.events_data:
             ctypes = self.axis_names
         else:
-            ctypes = np.array([self.primary_header["CTYPE%d" % (i)] for i in xrange(1,end)])
+            ctypes = np.array([self.primary_header["CTYPE%d" % (i)]
+                               for i in xrange(1,end)])
 
         log_str = "Detected these axes: "+"%s "*len(ctypes)
         mylog.info(log_str % tuple([ctype for ctype in ctypes]))
@@ -541,17 +553,19 @@
             self.wcs_2d.wcs.ctype = [self.wcs.wcs.ctype[self.lon_axis],
                                      self.wcs.wcs.ctype[self.lat_axis]]
 
-            self.wcs_1d = ap.pywcs.WCS(naxis=1)
-            self.wcs_1d.wcs.crpix = [self.wcs.wcs.crpix[self.vel_axis]]
-            self.wcs_1d.wcs.cdelt = [self.wcs.wcs.cdelt[self.vel_axis]]
-            self.wcs_1d.wcs.crval = [self.wcs.wcs.crval[self.vel_axis]]
-            self.wcs_1d.wcs.cunit = [str(self.wcs.wcs.cunit[self.vel_axis])]
-            self.wcs_1d.wcs.ctype = [self.wcs.wcs.ctype[self.vel_axis]]
+            x0 = self.wcs.wcs.crpix[self.vel_axis]
+            dz = self.wcs.wcs.cdelt[self.vel_axis]
+            z0 = self.wcs.wcs.crval[self.vel_axis]
+            self._zunit = str(self.wcs.wcs.cunit[self.vel_axis])
+
+            self.domain_left_edge[self.vel_axis] = \
+                (self.domain_left_edge[self.vel_axis]-x0)*dz + z0
+            self.domain_right_edge[self.vel_axis] = \
+                (self.domain_right_edge[self.vel_axis]-x0)*dz + z0
 
         else:
 
             self.wcs_2d = self.wcs
-            self.wcs_1d = None
             self.vel_axis = 2
             self.vel_name = "z"
 

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/frontends/fits/fields.py
--- a/yt/frontends/fits/fields.py
+++ b/yt/frontends/fits/fields.py
@@ -27,10 +27,6 @@
         w_coords = data.pf.wcs_2d.wcs_pix2world(data["x"], data["y"], 1)
         return w_coords[axis]
 
-    def _vel_los(field, data):
-        return data.pf.arr(data.pf.wcs_1d.wcs_pix2world(data["z"], 1)[0],
-                           str(data.pf.wcs_1d.wcs.cunit[0]))
-
     def _setup_ppv_fields(self):
 
         def world_f(axis, unit):
@@ -38,10 +34,6 @@
                 return data.pf.arr(self._get_2d_wcs(data, axis), unit)
             return _world_f
 
-        def _vel_los(field, data):
-            return data.pf.arr(data.pf.wcs_1d.wcs_pix2world(data["z"], 1)[0],
-                               str(data.pf.wcs_1d.wcs.cunit[0]))
-
         for (i, axis), name in zip(enumerate([self.pf.lon_axis, self.pf.lat_axis]),
                              [self.pf.lon_name, self.pf.lat_name]):
             unit = str(self.pf.wcs_2d.wcs.cunit[i])
@@ -49,13 +41,11 @@
             if unit.lower() == "rad": unit = "radian"
             self.add_field(("fits",name), function=world_f(axis, unit), units=unit)
 
-        if self.pf.dimensionality == 3:
-            unit = str(self.pf.wcs_1d.wcs.cunit[0])
-            self.add_field(("fits",self.pf.vel_name),
-                           function=_vel_los, units=unit)
-
     def setup_fluid_fields(self):
 
         if self.pf.ppv_data:
+            def _pixel(field, data):
+                return data.pf.arr(data["ones"], "pixel")
+            self.add_field(("fits","pixel"), function=_pixel, units="pixel")
             self._setup_ppv_fields()
             return

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/frontends/fits/io.py
--- a/yt/frontends/fits/io.py
+++ b/yt/frontends/fits/io.py
@@ -66,6 +66,7 @@
         ng = sum(len(c.objs) for c in chunks)
         mylog.debug("Reading %s cells of %s fields in %s grids",
                     size, [f2 for f1, f2 in fields], ng)
+        dx = self.pf.domain_width/self.pf.domain_dimensions
         for field in fields:
             ftype, fname = field
             tmp_fname = fname
@@ -78,11 +79,8 @@
             ind = 0
             for chunk in chunks:
                 for g in chunk.objs:
-                    centering = np.array([0.5]*3)
-                    if self.folded:
-                        centering[-1] = self.pf.domain_left_edge[2]
-                    start = (g.LeftEdge.ndarray_view()-centering).astype("int")
-                    end = (g.RightEdge.ndarray_view()-centering).astype("int")
+                    start = ((g.LeftEdge-self.pf.domain_left_edge)/dx).astype("int")
+                    end = ((g.RightEdge-self.pf.domain_left_edge)/dx).astype("int")
                     if self.folded:
                         my_off = \
                             self.pf.line_database.get(fname,

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -24,7 +24,6 @@
 
 from yt.utilities.exceptions import *
 from yt.utilities.logger import ytLogger as mylog
-from yt.utilities.definitions import inv_axis_names, axis_names, x_dict, y_dict
 import yt.extern.progressbar as pb
 import yt.utilities.rpdb as rpdb
 from yt.units.yt_array import YTArray, YTQuantity
@@ -637,8 +636,8 @@
         return os.environ.get("OMP_NUM_THREADS", 0)
     return nt
 
-def fix_axis(axis):
-    return inv_axis_names.get(axis, axis)
+def fix_axis(axis, pf):
+    return pf.coordinates.axis_id.get(axis, axis)
 
 def get_image_suffix(name):
     suffix = os.path.splitext(name)[1]

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/geometry/object_finding_mixin.py
--- a/yt/geometry/object_finding_mixin.py
+++ b/yt/geometry/object_finding_mixin.py
@@ -38,10 +38,12 @@
         # So if gRE > coord, we get a mask, if not, we get a zero
         #    if gLE > coord, we get a zero, if not, mask
         # Thus, if the coordinate is between the two edges, we win!
-        np.choose(np.greater(self.grid_right_edge[:,x_dict[axis]],coord[0]),(0,mask),mask)
-        np.choose(np.greater(self.grid_left_edge[:,x_dict[axis]],coord[0]),(mask,0),mask)
-        np.choose(np.greater(self.grid_right_edge[:,y_dict[axis]],coord[1]),(0,mask),mask)
-        np.choose(np.greater(self.grid_left_edge[:,y_dict[axis]],coord[1]),(mask,0),mask)
+        xax = self.pf.coordinates.x_axis[axis]
+        yax = self.pf.coordinates.y_axis[axis]
+        np.choose(np.greater(self.grid_right_edge[:,xax],coord[0]),(0,mask),mask)
+        np.choose(np.greater(self.grid_left_edge[:,xax],coord[0]),(mask,0),mask)
+        np.choose(np.greater(self.grid_right_edge[:,yax],coord[1]),(0,mask),mask)
+        np.choose(np.greater(self.grid_left_edge[:,yax],coord[1]),(mask,0),mask)
         ind = np.where(mask == 1)
         return self.grids[ind], ind
 

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/gui/reason/extdirect_repl.py
--- a/yt/gui/reason/extdirect_repl.py
+++ b/yt/gui/reason/extdirect_repl.py
@@ -39,7 +39,6 @@
 
 from yt.funcs import *
 from yt.utilities.logger import ytLogger, ufstring
-from yt.utilities.definitions import inv_axis_names
 from yt.visualization.image_writer import apply_colormap
 from yt.visualization.api import Streamlines
 from .widget_store import WidgetStore

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/gui/reason/widget_store.py
--- a/yt/gui/reason/widget_store.py
+++ b/yt/gui/reason/widget_store.py
@@ -61,10 +61,11 @@
             center = pf.h.find_max('Density')[1]
         else:
             center = np.array(center)
-        axis = inv_axis_names[axis.lower()]
+        axis = pf.coordinates.axis_id[axis.lower()]
         coord = center[axis]
         sl = pf.slice(axis, coord, center = center)
-        xax, yax = x_dict[axis], y_dict[axis]
+        xax = pf.coordinates.x_axis[axis]
+        yax = pf.coordinates.y_axis[axis]
         DLE, DRE = pf.domain_left_edge, pf.domain_right_edge
         pw = PWViewerExtJS(sl, (DLE[xax], DRE[xax], DLE[yax], DRE[yax]), 
                            setup = False, plot_type='SlicePlot')
@@ -82,9 +83,10 @@
 
     def create_proj(self, pf, axis, field, weight):
         if weight == "None": weight = None
-        axis = inv_axis_names[axis.lower()]
+        axis = pf.coordinates.axis_id[axis.lower()]
         proj = pf.proj(field, axis, weight_field=weight)
-        xax, yax = x_dict[axis], y_dict[axis]
+        xax = pf.coordinates.x_axis[axis]
+        yax = pf.coordinates.y_axis[axis]
         DLE, DRE = pf.domain_left_edge, pf.domain_right_edge
         pw = PWViewerExtJS(proj, (DLE[xax], DRE[xax], DLE[yax], DRE[yax]),
                            setup = False, plot_type='ProjectionPlot')

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/utilities/answer_testing/output_tests.py
--- a/yt/utilities/answer_testing/output_tests.py
+++ b/yt/utilities/answer_testing/output_tests.py
@@ -177,8 +177,8 @@
         This is a helper function that returns a 2D array of the specified
         source, in the specified field, at the specified spatial extent.
         """
-        xax = x_dict[self.axis]
-        yax = y_dict[self.axis]
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
         
         if edges is None:
             edges = (self.pf.domain_left_edge[xax],

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/utilities/definitions.py
--- a/yt/utilities/definitions.py
+++ b/yt/utilities/definitions.py
@@ -21,20 +21,6 @@
 # The number of levels we expect to have at most
 MAXLEVEL=48
 
-axis_labels = [('y','z'),('x','z'),('x','y')]
-axis_names = {0: 'x', 1: 'y', 2: 'z', 4:''}
-inv_axis_names = {'x':0,'y':1,'z':2,
-                  'X':0,'Y':1,'Z':2}
-
-vm_axis_names = {0:'x', 1:'y', 2:'z', 3:'dx', 4:'dy'}
-
-# The appropriate axes for which way we are slicing
-x_dict = [1,0,0]
-y_dict = [2,2,1]
-
-x_names = ['y','x','x']
-y_names = ['z','z','y']
-
 # How many of each thing are in an Mpc
 mpc_conversion = {'Mpc'   : mpc_per_mpc,
                   'mpc'   : mpc_per_mpc,
@@ -56,5 +42,3 @@
                   'Myr'   : sec_per_Myr,
                   'years' : sec_per_year,
                   'days'  : sec_per_day}
-
-axis_labels = [('y','z'),('x','z'),('x','y')]

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/utilities/parallel_tools/parallel_analysis_interface.py
--- a/yt/utilities/parallel_tools/parallel_analysis_interface.py
+++ b/yt/utilities/parallel_tools/parallel_analysis_interface.py
@@ -27,8 +27,6 @@
     ensure_list, iterable, traceback_writer_hook
 
 from yt.config import ytcfg
-from yt.utilities.definitions import \
-    x_dict, y_dict
 import yt.utilities.logger
 from yt.utilities.lib.QuadTree import \
     QuadTree, merge_quadtrees
@@ -1066,7 +1064,8 @@
            return False, self.index.grid_collection(self.center,
                                                         self.index.grids)
 
-        xax, yax = x_dict[axis], y_dict[axis]
+        xax = self.pf.coordinates.x_axis[axis]
+        yax = self.pf.coordinates.y_axis[axis]
         cc = MPI.Compute_dims(self.comm.size, 2)
         mi = self.comm.rank
         cx, cy = np.unravel_index(mi, cc)

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -17,7 +17,7 @@
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \
-    get_image_suffix, mylog, x_dict, y_dict
+    get_image_suffix, mylog
 import numpy as np
 
 class CallbackWrapper(object):
@@ -30,8 +30,8 @@
             self.image = self._axes.images[0]
         if frb.axis < 3:
             DD = frb.pf.domain_width
-            xax = x_dict[frb.axis]
-            yax = y_dict[frb.axis]
+            xax = frb.pf.coordinates.x_axis[frb.axis]
+            yax = frb.pf.coordinates.y_axis[frb.axis]
             self._period = (DD[xax], DD[yax])
         self.pf = frb.pf
         self.xlim = viewer.xlim

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/visualization/eps_writer.py
--- a/yt/visualization/eps_writer.py
+++ b/yt/visualization/eps_writer.py
@@ -19,11 +19,6 @@
 from _mpl_imports import FigureCanvasAgg
 
 from yt.utilities.logger import ytLogger as mylog
-from yt.utilities.definitions import \
-    x_dict, x_names, \
-    y_dict, y_names, \
-    axis_names, \
-    axis_labels
 from .plot_window import PlotWindow
 from .profile_plotter import PhasePlot
 from .plot_modifications import get_smallest_appropriate_unit
@@ -296,6 +291,7 @@
             _yrange = (0, width * plot.pf[units])
             _xlog = False
             _ylog = False
+            axis_names = plot.pf.coordinates.axis_name
             if bare_axes:
                 _xlabel = ""
                 _ylabel = ""
@@ -305,14 +301,16 @@
                     _xlabel = xlabel
                 else:
                     if data.axis != 4:
-                        _xlabel = '%s (%s)' % (x_names[data.axis], units)
+                        xax = plot.pf.coordinates.x_axis[data.axis]
+                        _xlabel = '%s (%s)' % (axis_names[xax], units)
                     else:
                         _xlabel = 'Image x (%s)' % (units)
                 if ylabel != None:
                     _ylabel = ylabel
                 else:
                     if data.axis != 4:
-                        _ylabel = '%s (%s)' % (y_names[data.axis], units)
+                        yax = plot.pf.coordinatesyx_axis[data.axis]
+                        _ylabel = '%s (%s)' % (axis_names[yax], units)
                     else:
                         _ylabel = 'Image y (%s)' % (units)
             if tickcolor == None:

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/visualization/fixed_resolution.py
--- a/yt/visualization/fixed_resolution.py
+++ b/yt/visualization/fixed_resolution.py
@@ -14,10 +14,6 @@
 #-----------------------------------------------------------------------------
 
 from yt.funcs import *
-from yt.utilities.definitions import \
-    x_dict, \
-    y_dict, \
-    axis_names
 from .volume_rendering.api import off_axis_projection
 from yt.data_objects.image_array import ImageArray
 from yt.utilities.lib.misc_utilities import \
@@ -104,8 +100,8 @@
             DRE = self.pf.domain_right_edge
             DD = float(self.periodic)*(DRE - DLE)
             axis = self.data_source.axis
-            xax = x_dict[axis]
-            yax = y_dict[axis]
+            xax = self.pf.coordinates.x_axis[axis]
+            yax = self.pf.coordinates.y_axis[axis]
             self._period = (DD[xax], DD[yax])
             self._edges = ( (DLE[xax], DRE[xax]), (DLE[yax], DRE[yax]) )
         
@@ -334,10 +330,10 @@
     @property
     def limits(self):
         rv = dict(x = None, y = None, z = None)
-        xax = x_dict[self.axis]
-        yax = y_dict[self.axis]
-        xn = axis_names[xax]
-        yn = axis_names[yax]
+        xax = self.pf.coordinates.x_axis[self.axis]
+        yax = self.pf.coordinates.y_axis[self.axis]
+        xn = self.pf.coordinates.axis_name[xax]
+        yn = self.pf.coordinates.axis_name[yax]
         rv[xn] = (self.bounds[0], self.bounds[1])
         rv[yn] = (self.bounds[2], self.bounds[3])
         return rv

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/visualization/image_panner/vm_panner.py
--- a/yt/visualization/image_panner/vm_panner.py
+++ b/yt/visualization/image_panner/vm_panner.py
@@ -19,8 +19,6 @@
     FixedResolutionBuffer, ObliqueFixedResolutionBuffer
 from yt.data_objects.data_containers import \
     data_object_registry
-from yt.utilities.definitions import \
-    x_dict, y_dict
 from yt.funcs import *
 
 class VariableMeshPanner(object):
@@ -62,7 +60,8 @@
         if not hasattr(self, 'pf'): self.pf = self.source.pf
         DLE, DRE = self.pf.domain_left_edge, self.pf.domain_right_edge
         ax = self.source.axis
-        xax, yax = x_dict[ax], y_dict[ax]
+        xax = self.pf.coordinates.x_axis[ax]
+        yax = self.pf.coordinates.y_axis[ax]
         xbounds = DLE[xax], DRE[xax]
         ybounds = DLE[yax], DRE[yax]
         return (xbounds, ybounds)
@@ -183,8 +182,10 @@
         if len(center) == 2:
             centerx, centery = center
         elif len(center) == 3:
-            centerx = center[x_dict[self.source.axis]]
-            centery = center[y_dict[self.source.axis]]
+            xax = self.pf.coordinates.x_axis[self.source.axis]
+            yax = self.pf.coordinates.y_axis[self.source.axis]
+            centerx = center[xax]
+            centery = center[yax]
         else:
             raise RuntimeError
         Wx, Wy = self.width

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/visualization/plot_container.py
--- a/yt/visualization/plot_container.py
+++ b/yt/visualization/plot_container.py
@@ -17,7 +17,6 @@
 from yt.funcs import \
     defaultdict, get_image_suffix, \
     get_ipython_api_version
-from yt.utilities.definitions import axis_names
 from yt.utilities.exceptions import \
     YTNotInsideNotebook
 from ._mpl_imports import FigureCanvasAgg
@@ -424,7 +423,8 @@
             for k, v in self.plots.iteritems():
                 names.append(v.save(name, mpl_kwargs))
             return names
-        axis = axis_names[self.data_source.axis]
+        axis = self.pf.coordinates.axis_name.get(
+            self.data_source.axis, '')
         weight = None
         type = self._plot_type
         if type in ['Projection', 'OffAxisProjection']:

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -18,11 +18,6 @@
 
 from yt.funcs import *
 from _mpl_imports import *
-from yt.utilities.definitions import \
-    x_dict, x_names, \
-    y_dict, y_names, \
-    axis_names, \
-    axis_labels
 from yt.utilities.physical_constants import \
     sec_per_Gyr, sec_per_Myr, \
     sec_per_kyr, sec_per_year, \
@@ -115,13 +110,17 @@
                                         "cutting_plane_velocity_y",
                                         self.factor)
         else:
-            xv = "velocity_%s" % (x_names[plot.data.axis])
-            yv = "velocity_%s" % (y_names[plot.data.axis])
+            ax = plot.data.axis
+            (xi, yi) = (plot.data.pf.coordinates.x_axis[ax],
+                        plot.data.pf.coordinates.y_axis[ax])
+            axis_names = plot.data.pf.coordinates.axis_name
+            xv = "velocity_%s" % (axis_names[xi])
+            yv = "velocity_%s" % (axis_names[yi])
 
             bv = plot.data.get_field_parameter("bulk_velocity")
             if bv is not None:
-                bv_x = bv[x_dict[plot.data.axis]]
-                bv_y = bv[y_dict[plot.data.axis]]
+                bv_x = bv[xi]
+                bv_y = bv[yi]
             else: bv_x = bv_y = YTQuantity(0, 'cm/s')
 
             qcb = QuiverCallback(xv, yv, self.factor, scale=self.scale, 
@@ -156,8 +155,11 @@
                                         "cutting_plane_by",
                                         self.factor)
         else:
-            xv = "magnetic_field_%s" % (x_names[plot.data.axis])
-            yv = "magnetic_field_%s" % (y_names[plot.data.axis])
+            xax = plot.data.pf.coordinates.x_axis[plot.data.axis]
+            yax = plot.data.pf.coordinates.y_axis[plot.data.axis]
+            axis_names = plot.data.pf.coordinates.axis_name
+            xv = "magnetic_field_%s" % (axis_names[xax])
+            yv = "magnetic_field_%s" % (axis_names[yax])
             qcb = QuiverCallback(xv, yv, self.factor, scale=self.scale, scale_units=self.scale_units, normalize=self.normalize)
         return qcb(plot)
 
@@ -194,8 +196,10 @@
         # periodicity
         ax = plot.data.axis
         pf = plot.data.pf
-        period_x = pf.domain_width[x_dict[ax]]
-        period_y = pf.domain_width[y_dict[ax]]
+        (xi, yi) = (pf.coordinates.x_axis[ax],
+                    pf.coordinates.y_axis[ax])
+        period_x = pf.domain_width[xi]
+        period_y = pf.domain_width[yi]
         periodic = int(any(pf.periodicity))
         fv_x = plot.data[self.field_x]
         if self.bv_x != 0.0:
@@ -384,8 +388,9 @@
         yy0, yy1 = plot._axes.get_ylim()
         (dx, dy) = self.pixel_scale(plot)
         (xpix, ypix) = plot.image._A.shape
-        px_index = x_dict[plot.data.axis]
-        py_index = y_dict[plot.data.axis]
+        ax = plot.data.axis
+        px_index = plot.data.pf.coordinates.x_axis[ax]
+        py_index = plot.data.pf.coordinates.y_axis[ax]
         DW = plot.data.pf.domain_width
         if self.periodic:
             pxs, pys = np.mgrid[-1:1:3j,-1:1:3j]
@@ -650,11 +655,12 @@
 
         plot._axes.hold(True)
 
-        px_index = x_dict[plot.data.axis]
-        py_index = y_dict[plot.data.axis]
+        ax = plot.data.axis
+        px_index = plot.data.pf.coordinates.x_axis[ax]
+        py_index = plot.data.pf.coordinates.y_axis[ax]
 
-        xf = axis_names[px_index]
-        yf = axis_names[py_index]
+        xf = plot.data.pf.coordinates.axis_name[px_index]
+        yf = plot.data.pf.coordinates.axis_name[py_index]
         dxf = "d%s" % xf
         dyf = "d%s" % yf
 
@@ -701,8 +707,10 @@
 
     def __call__(self, plot):
         if len(self.pos) == 3:
-            pos = (self.pos[x_dict[plot.data.axis]],
-                   self.pos[y_dict[plot.data.axis]])
+            ax = plot.data.axis
+            (xi, yi) = (plot.data.pf.coordinates.x_axis[ax],
+                        plot.data.pf.coordinates.y_axis[ax])
+            pos = self.pos[xi], self.pos[yi]
         else: pos = self.pos
         if isinstance(self.code_size[1], basestring):
             code_size = plot.data.pf.quan(*self.code_size).value
@@ -732,8 +740,10 @@
 
     def __call__(self, plot):
         if len(self.pos) == 3:
-            pos = (self.pos[x_dict[plot.data.axis]],
-                   self.pos[y_dict[plot.data.axis]])
+            ax = plot.data.axis
+            (xi, yi) = (plot.data.pf.coordinates.x_axis[ax],
+                        plot.data.pf.coordinates.y_axis[ax])
+            pos = self.pos[xi], self.pos[yi]
         else: pos = self.pos
         width,height = plot.image._A.shape
         x,y = self.convert_to_plot(plot, pos)
@@ -758,8 +768,10 @@
         xx0, xx1 = plot._axes.get_xlim()
         yy0, yy1 = plot._axes.get_ylim()
         if len(self.pos) == 3:
-            pos = (self.pos[x_dict[plot.data.axis]],
-                   self.pos[y_dict[plot.data.axis]])
+            ax = plot.data.axis
+            (xi, yi) = (plot.data.pf.coordinates.x_axis[ax],
+                        plot.data.pf.coordinates.y_axis[ax])
+            pos = self.pos[xi], self.pos[yi]
         elif len(self.pos) == 2:
             pos = self.pos
         x,y = self.convert_to_plot(plot, pos)
@@ -802,7 +814,9 @@
         if plot.data.axis == 4:
             (xi, yi) = (0, 1)
         else:
-            (xi, yi) = (x_dict[plot.data.axis], y_dict[plot.data.axis])
+            ax = plot.data.axis
+            (xi, yi) = (plot.data.pf.coordinates.x_axis[ax],
+                        plot.data.pf.coordinates.y_axis[ax])
 
         (center_x,center_y) = self.convert_to_plot(plot,(self.center[xi], self.center[yi]))
         
@@ -853,7 +867,9 @@
             radius = halo.maximum_radius() * self.pixel_scale(plot)[0]
             center = halo.center_of_mass()
             
-            (xi, yi) = (x_dict[plot.data.axis], y_dict[plot.data.axis])
+            ax = plot.data.axis
+            (xi, yi) = (plot.data.pf.coordinates.x_axis[ax],
+                        plot.data.pf.coordinates.y_axis[ax])
 
             (center_x,center_y) = self.convert_to_plot(plot,(center[xi], center[yi]))
             color = np.ones(3) * (0.4 * (num - halo.id)/ num) + 0.6
@@ -892,7 +908,10 @@
     def __call__(self,plot):
         (dx,dy) = self.pixel_scale(plot)
 
-        (xi, yi) = (x_names[plot.data.axis], y_names[plot.data.axis])
+        xax = plot.data.pf.coordinates.x_axis[plot.data.axis]
+        yax = plot.data.pf.coordinates.y_axis[plot.data.axis]
+        axis_names = plot.data.pf.coordinates.axis_name
+        (xi, yi) = (axis_names[xax], axis_names[yax])
 
         # now we loop over the haloes
         for halo in self.hop_output[:self.max_number]:
@@ -940,8 +959,10 @@
         kwargs = self.text_args.copy()
         if self.data_coords and len(plot.image._A.shape) == 2:
             if len(self.pos) == 3:
-                pos = (self.pos[x_dict[plot.data.axis]],
-                       self.pos[y_dict[plot.data.axis]])
+                ax = plot.data.axis
+                (xi, yi) = (plot.data.pf.coordinates.x_axis[ax],
+                            plot.data.pf.coordinates.y_axis[ax])
+                pos = self.pos[xi], self.pos[yi]
             else: pos = self.pos
             x,y = self.convert_to_plot(plot, pos)
         else:
@@ -992,8 +1013,12 @@
         xx0, xx1 = plot._axes.get_xlim()
         yy0, yy1 = plot._axes.get_ylim()
         reg = self._get_region((x0,x1), (y0,y1), plot.data.axis, data)
-        field_x = "particle_position_%s" % axis_names[x_dict[data.axis]]
-        field_y = "particle_position_%s" % axis_names[y_dict[data.axis]]
+        ax = data.axis
+        xax = plot.data.pf.coordinates.x_axis[ax]
+        yax = plot.data.pf.coordinates.y_axis[ax]
+        axis_names = plot.data.pf.coordinates.axis_name
+        field_x = "particle_position_%s" % axis_names[xax]
+        field_y = "particle_position_%s" % axis_names[yax]
         gg = ( ( reg[field_x] >= x0 ) & ( reg[field_x] <= x1 )
            &   ( reg[field_y] >= y0 ) & ( reg[field_y] <= y1 ) )
         if self.ptype is not None:
@@ -1021,8 +1046,9 @@
 
     def _get_region(self, xlim, ylim, axis, data):
         LE, RE = [None]*3, [None]*3
-        xax = x_dict[axis]
-        yax = y_dict[axis]
+        pf = data.pf
+        xax = pf.coordinates.x_axis[axis]
+        yax = pf.coordinates.y_axis[axis]
         zax = axis
         LE[xax], RE[xax] = xlim
         LE[yax], RE[yax] = ylim
@@ -1240,7 +1266,9 @@
 
     def __call__(self, plot):
         plot._axes.hold(True)
-        xax, yax = x_dict[plot.data.axis], y_dict[plot.data.axis]
+        ax = data.axis
+        xax = plot.data.pf.coordinates.x_axis[ax]
+        yax = plot.data.pf.coordinates.y_axis[ax]
         l_cy = triangle_plane_intersect(plot.data.axis, plot.data.coord, self.vertices)[:,:,(xax, yax)]
         lc = matplotlib.collections.LineCollection(l_cy, **self.plot_args)
         plot._axes.add_collection(lc)

diff -r e2b0a076cd3d084752bf56b1ce4ead485f241d59 -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -43,8 +43,6 @@
 from yt.utilities.png_writer import \
     write_png_to_string
 from yt.utilities.definitions import \
-    x_dict, y_dict, \
-    axis_names, axis_labels, \
     formatted_length_unit_names
 from yt.utilities.math_utils import \
     ortho_find
@@ -108,7 +106,9 @@
     if width is None:
         # Default to code units
         if not iterable(axis):
-            w = pf.domain_width[[x_dict[axis], y_dict[axis]]]
+            xax = pf.coordinates.x_axis[axis]
+            yax = pf.coordinates.y_axis[axis]
+            w = pf.domain_width[[xax, yax]]
         else:
             # axis is actually the normal vector
             # for an off-axis data object.
@@ -189,10 +189,12 @@
             center[2] = 0.0
     else:
         raise NotImplementedError
-    bounds = (center[x_dict[axis]]-width[0] / 2,
-              center[x_dict[axis]]+width[0] / 2,
-              center[y_dict[axis]]-width[1] / 2,
-              center[y_dict[axis]]+width[1] / 2)
+    xax = pf.coordinates.x_axis[axis]
+    yax = pf.coordinates.y_axis[axis]
+    bounds = (center[xax]-width[0] / 2,
+              center[xax]+width[0] / 2,
+              center[yax]-width[1] / 2,
+              center[yax]+width[1] / 2)
     return (bounds, center)
 
 def get_oblique_window_parameters(normal, center, width, pf, depth=None):
@@ -702,10 +704,12 @@
             xllim, xrlim = self.xlim
             yllim, yrlim = self.ylim
         elif origin[2] == 'domain':
-            xllim = self.pf.domain_left_edge[x_dict[axis_index]]
-            xrlim = self.pf.domain_right_edge[x_dict[axis_index]]
-            yllim = self.pf.domain_left_edge[y_dict[axis_index]]
-            yrlim = self.pf.domain_right_edge[y_dict[axis_index]]
+            xax = pf.coordinates.x_axis[axis_index]
+            yax = pf.coordinates.y_axis[axis_index]
+            xllim = self.pf.domain_left_edge[xax]
+            xrlim = self.pf.domain_right_edge[xax]
+            yllim = self.pf.domain_left_edge[yax]
+            yrlim = self.pf.domain_right_edge[yax]
         elif origin[2] == 'native':
             return (self.pf.quan(0.0, 'code_length'),
                     self.pf.quan(0.0, 'code_length'))
@@ -853,6 +857,11 @@
                     label.set_fontproperties(fp)
 
             else:
+                axis_names = self.pf.coordinates.axis_name
+                xax = self.pf.coordinates.x_axis[axis_index]
+                yax = self.pf.coordinates.y_axis[axis_index]
+                labels = [r'$\rm{'+axis_names[xax]+axes_unit_labels[0] + r'}$',
+                          r'$\rm{'+axis_names[yax]+axes_unit_labels[1] + r'}$']
 
                 axis = self.data_source.axis
                 wcs_axes = self.plots[f].figure.axes[-1]
@@ -1042,7 +1051,7 @@
         ts = self._initialize_dataset(pf)
         self.ts = ts
         pf = self.pf = ts[0]
-        axis = fix_axis(axis)
+        axis = fix_axis(axis, pf)
         (bounds, center) = get_window_parameters(axis, center, width, pf)
         if field_parameters is None: field_parameters = {}
         slc = pf.slice(axis, center[axis],
@@ -1168,7 +1177,7 @@
         ts = self._initialize_dataset(pf)
         self.ts = ts
         pf = self.pf = ts[0]
-        axis = fix_axis(axis)
+        axis = fix_axis(axis, pf)
         (bounds, center) = get_window_parameters(axis, center, width, pf)
         if field_parameters is None: field_parameters = {}
         proj = pf.proj(fields, axis, weight_field=weight_field,
@@ -1498,8 +1507,11 @@
                         self._frb.bounds, (nx,ny))
 
         axis = self._frb.data_source.axis
-        fx = "%s-velocity" % (axis_names[x_dict[axis]])
-        fy = "%s-velocity" % (axis_names[y_dict[axis]])
+        xax = self._frb.data_source.pf.coordinates.x_axis[axis]
+        yax = self._frb.data_source.pf.coordinates.y_axis[axis]
+        axis_names = self._frb.data_source.pf.coordinates.axis_name
+        fx = "velocity_%s" % (axis_names[xax])
+        fy = "velocity_%x" % (axis_names[yax])
         px = new_frb[fx][::-1,:]
         py = new_frb[fy][::-1,:]
         x = np.mgrid[0:vi-1:ny*1j]
@@ -1583,12 +1595,14 @@
             unit = self._axes_unit_names
         units = self.get_field_units(field, strip_mathml)
         center = getattr(self._frb.data_source, "center", None)
+        xax = self.pf.coordinates.x_axis[self._frb.axis]
+        yax = self.pf.coordinates.y_axis[self._frb.axis]
         if center is None or self._frb.axis == 4:
             xc, yc, zc = -999, -999, -999
         else:
-            center[x_dict[self._frb.axis]] = 0.5 * (
+            center[xax] = 0.5 * (
                 self.xlim[0] + self.xlim[1])
-            center[y_dict[self._frb.axis]] = 0.5 * (
+            center[yax] = 0.5 * (
                 self.ylim[0] + self.ylim[1])
             xc, yc, zc = center
         if return_string:


https://bitbucket.org/yt_analysis/yt/commits/4286e6390a7b/
Changeset:   4286e6390a7b
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-29 16:33:44
Summary:     Fixing a result of a bad merge
Affected #:  9 files

diff -r 6e4ab9ba567167ffcc64bd4732f5de665f589f18 -r 4286e6390a7b71c830068a91fe00ac32b5a03757 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -844,8 +844,11 @@
                     labels = [r'$\rm{Image\/x'+axes_unit_labels[0]+'}$',
                               r'$\rm{Image\/y'+axes_unit_labels[1]+'}$']
                 else:
-                    labels = [r'$\rm{'+axis_labels[axis_index][i]+
-                              axes_unit_labels[i] + r'}$' for i in (0,1)]
+                    axis_names = self.pf.coordinates.axis_name
+                    xax = self.pf.coordinates.x_axis[axis_index]
+                    yax = self.pf.coordinates.y_axis[axis_index]
+                    labels = [r'$\rm{'+axis_names[xax]+axes_unit_labels[0] + r'}$',
+                              r'$\rm{'+axis_names[yax]+axes_unit_labels[1] + r'}$']
 
                 self.plots[f].axes.set_xlabel(labels[0],fontproperties=fp)
                 self.plots[f].axes.set_ylabel(labels[1],fontproperties=fp)
@@ -857,11 +860,6 @@
                     label.set_fontproperties(fp)
 
             else:
-                axis_names = self.pf.coordinates.axis_name
-                xax = self.pf.coordinates.x_axis[axis_index]
-                yax = self.pf.coordinates.y_axis[axis_index]
-                labels = [r'$\rm{'+axis_names[xax]+axes_unit_labels[0] + r'}$',
-                          r'$\rm{'+axis_names[yax]+axes_unit_labels[1] + r'}$']
 
                 axis = self.data_source.axis
                 wcs_axes = self.plots[f].figure.axes[-1]


https://bitbucket.org/yt_analysis/yt/commits/ad6c28383ac2/
Changeset:   ad6c28383ac2
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-29 17:15:50
Summary:     Merge in changes from yt-3.0
Affected #:  10 files

diff -r 4286e6390a7b71c830068a91fe00ac32b5a03757 -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 yt/analysis_modules/halo_analysis/halo_finding_methods.py
--- a/yt/analysis_modules/halo_analysis/halo_finding_methods.py
+++ /dev/null
@@ -1,141 +0,0 @@
-"""
-Halo Finding methods
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-
-from yt.analysis_modules.halo_finding.halo_objects import \
-    FOFHaloFinder, HOPHaloFinder
-from yt.frontends.halo_catalogs.halo_catalog.data_structures import \
-    HaloCatalogDataset
-from yt.frontends.stream.data_structures import \
-    load_particles
-
-from .operator_registry import \
-    finding_method_registry
-
-
-def add_finding_method(name, function):
-    finding_method_registry[name] = HaloFindingMethod(function)
-    
-class HaloFindingMethod(object):
-    r"""
-    A halo finding method is a callback that performs halo finding on a 
-    dataset and returns a new dataset that is the loaded halo finder output.
-    """
-    def __init__(self, function, args=None, kwargs=None):
-        self.function = function
-        self.args = args
-        if self.args is None: self.args = []
-        self.kwargs = kwargs
-        if self.kwargs is None: self.kwargs = {}
-
-    def __call__(self, ds):
-        return self.function(ds, *self.args, **self.kwargs)
-
-def _hop_method(pf):
-    r"""
-    Run the Hop halo finding method.
-    """
-    
-    halo_list = HOPHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("hop", _hop_method)
-
-def _fof_method(pf):
-    r"""
-    Run the FoF halo finding method.
-    """
-
-    halo_list = FOFHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("fof", _fof_method)
-
-def _rockstar_method(pf):
-    r"""
-    Run the Rockstar halo finding method.
-    """
-
-    from yt.frontends.halo_catalogs.rockstar.data_structures import \
-     RockstarDataset
-    from yt.analysis_modules.halo_finding.rockstar.api import \
-     RockstarHaloFinder
-    
-    rh = RockstarHaloFinder(pf)
-    rh.run()
-
-
-    halos_pf = RockstarDataset("rockstar_halos/halos_0.0.bin")
-    try:
-        halos_pf.create_field_info()
-    except ValueError:
-        return None
-
-    return halos_pf
-add_finding_method("rockstar", _rockstar_method)
-
-def _parse_old_halo_list(data_pf, halo_list):
-    r"""
-    Convert the halo list into a loaded dataset.
-    """
-
-    num_halos = len(halo_list)
-
-    if num_halos == 0: return None
-
-    # Set up fields that we want to pull from identified halos and their units
-    new_fields = ['particle_identifier', 'particle_mass', 'particle_position_x', 
-        'particle_position_y','particle_position_z',
-        'virial_radius']
-    new_units = [ '', 'g', 'cm', 'cm','cm','cm']
-
-    # Set up a dictionary based on those fields 
-    # with empty arrays where we will fill in their values
-    halo_properties = { f : (np.zeros(num_halos),unit) \
-        for f, unit in zip(new_fields,new_units)}
-
-    # Iterate through the halos pulling out their positions and virial quantities
-    # and filling in the properties dictionary
-    for i,halo in enumerate(halo_list):
-        halo_properties['particle_identifier'][0][i] = i
-        halo_properties['particle_mass'][0][i] = halo.virial_mass().in_cgs()
-        halo_properties['virial_radius'][0][i] = halo.virial_radius().in_cgs()
-
-        com = halo.center_of_mass().in_cgs()
-        halo_properties['particle_position_x'][0][i] = com[0]
-        halo_properties['particle_position_y'][0][i] = com[1]
-        halo_properties['particle_position_z'][0][i] = com[2]
-
-    # Define a bounding box based on original data pf
-    bbox = np.array([data_pf.domain_left_edge.in_cgs(),
-            data_pf.domain_right_edge.in_cgs()]).T
-
-    # Create a pf with the halos as particles
-    particle_pf = load_particles(halo_properties, 
-            bbox=bbox, length_unit = 1, mass_unit=1)
-
-    # Create the field info dictionary so we can reference those fields
-    particle_pf.create_field_info()
-
-    for attr in ["current_redshift", "current_time",
-                 "domain_dimensions",
-                 "cosmological_simulation", "omega_lambda",
-                 "omega_matter", "hubble_constant"]:
-        attr_val = getattr(data_pf, attr)
-        setattr(particle_pf, attr, attr_val)
-    particle_pf.current_time = particle_pf.current_time.in_cgs()
-    
-    return particle_pf

diff -r 4286e6390a7b71c830068a91fe00ac32b5a03757 -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 4286e6390a7b71c830068a91fe00ac32b5a03757 -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r 4286e6390a7b71c830068a91fe00ac32b5a03757 -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 4286e6390a7b71c830068a91fe00ac32b5a03757 -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -185,24 +185,24 @@
         for i, fits_file in enumerate(self.parameter_file._fits_files):
             for j, hdu in enumerate(fits_file):
                 if self._ensure_same_dims(hdu):
-                    if len(self.pf.override_fields) > 0:
-                        field = self.pf.override_fields.pop(0)
-                        fname = field[0]
-                        units = field[1]
-                    else:
-                        units = self._determine_image_units(hdu.header, known_units)
-                        try:
-                            # Grab field name from btype
-                            fname = hdu.header["btype"].lower()
-                        except:
-                            # Try to guess the name from the units
-                            fname = self._guess_name_from_units(units)
-                            # When all else fails
-                            if fname is None: fname = "image_%d" % (j)
-                        if self.pf.num_files > 1: fname += "_file_%d" % (i)
+                    units = self._determine_image_units(hdu.header, known_units)
+                    try:
+                        # Grab field name from btype
+                        fname = hdu.header["btype"].lower()
+                    except:
+                        # Try to guess the name from the units
+                        fname = self._guess_name_from_units(units)
+                        # When all else fails
+                        if fname is None: fname = "image_%d" % (j)
+                    if self.pf.num_files > 1 and fname.startswith("image"):
+                        fname += "_file_%d" % (i)
                     for k in xrange(naxis4):
                         if naxis4 > 1:
                             fname += "_%s_%d" % (hdu.header["CTYPE4"], k+1)
+                        if fname in self.field_list:
+                            mylog.error("You have two fields with the same name. Change one of " +
+                                        "the names in the BTYPE header keyword to distinguish " +
+                                        "them.")
                         self._axis_map[fname] = k
                         self._file_map[fname] = fits_file
                         self._ext_map[fname] = j
@@ -219,7 +219,6 @@
                                   "the same dimensions as the primary and will not be " +
                                   "available as a field.")
 
-
         # For line fields, we still read the primary field. Not sure how to extend this
         # For now, we pick off the first field from the field list.
         line_db = self.parameter_file.line_database
@@ -317,17 +316,12 @@
                  folded_width = None,
                  line_database = None,
                  suppress_astropy_warnings = True,
-                 parameters = None,
-                 override_fields = None):
+                 parameters = None):
 
         if parameters is None:
             parameters = {}
         self.specified_parameters = parameters
 
-        if override_fields is None:
-            override_fields = []
-        self.override_fields = override_fields
-
         self.folded_axis = folded_axis
         self.folded_width = folded_width
         self._unfolded_domain_dimensions = None
@@ -556,7 +550,7 @@
             x0 = self.wcs.wcs.crpix[self.vel_axis]
             dz = self.wcs.wcs.cdelt[self.vel_axis]
             z0 = self.wcs.wcs.crval[self.vel_axis]
-            self._zunit = str(self.wcs.wcs.cunit[self.vel_axis])
+            self.vunit = str(self.wcs.wcs.cunit[self.vel_axis])
 
             self.domain_left_edge[self.vel_axis] = \
                 (self.domain_left_edge[self.vel_axis]-x0)*dz + z0
@@ -568,6 +562,7 @@
             self.wcs_2d = self.wcs
             self.vel_axis = 2
             self.vel_name = "z"
+            self.vunit = "code length"
 
     def __del__(self):
         for file in self._fits_files:

diff -r 4286e6390a7b71c830068a91fe00ac32b5a03757 -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 yt/frontends/fits/fields.py
--- a/yt/frontends/fits/fields.py
+++ b/yt/frontends/fits/fields.py
@@ -23,11 +23,11 @@
         for field in pf.field_list:
             if field[0] == "fits": self[field].take_log = False
 
-    def _get_2d_wcs(self, data, axis):
-        w_coords = data.pf.wcs_2d.wcs_pix2world(data["x"], data["y"], 1)
-        return w_coords[axis]
+    def _setup_ppv_fields(self):
 
-    def _setup_ppv_fields(self):
+        def _get_2d_wcs(self, data, axis):
+            w_coords = data.pf.wcs_2d.wcs_pix2world(data["x"], data["y"], 1)
+            return w_coords[axis]
 
         def world_f(axis, unit):
             def _world_f(field, data):
@@ -41,6 +41,13 @@
             if unit.lower() == "rad": unit = "radian"
             self.add_field(("fits",name), function=world_f(axis, unit), units=unit)
 
+        if self.pf.dimensionality == 3:
+            def _vel_los(field, data):
+                axis = "xyz"[data.pf.vel_axis]
+                return data.pf.arr(data[axis].ndarray_view(),data.pf.vunit)
+            self.add_field(("fits",data.pf.vel_name), function=_vel_los,
+                           units=data.pf.vunit)
+
     def setup_fluid_fields(self):
 
         if self.pf.ppv_data:

diff -r 4286e6390a7b71c830068a91fe00ac32b5a03757 -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 yt/frontends/fits/setup.py
--- a/yt/frontends/fits/setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('fits', parent_package, top_path)
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 4286e6390a7b71c830068a91fe00ac32b5a03757 -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 yt/frontends/fits/tests/test_outputs.py
--- a/yt/frontends/fits/tests/test_outputs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-FITS frontend tests
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from yt.testing import *
-from yt.utilities.answer_testing.framework import \
-    requires_pf, \
-    small_patch_amr, \
-    big_patch_amr, \
-    data_dir_load
-
-_fields = ("intensity")
-
-m33 = "fits/m33_hi.fits"
- at requires_pf(m33, big_data=True)
-def test_m33():
-    pf = data_dir_load(m33)
-    yield assert_equal, str(pf), "m33_hi.fits"
-    for test in small_patch_amr(m33, _fields):
-        test_m33.__name__ = test.description
-        yield test
-
-_fields = ("x-velocity","y-velocity","z-velocity")
-
-vf = "fits/velocity_field_20.fits"
- at requires_pf(vf)
-def test_velocity_field():
-    pf = data_dir_load(bf)
-    yield assert_equal, str(pf), "velocity_field_20.fits"
-    for test in small_patch_amr(vf, _fields):
-        test_velocity_field.__name__ = test.description
-        yield test


https://bitbucket.org/yt_analysis/yt/commits/45b7456c9d98/
Changeset:   45b7456c9d98
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-29 18:05:15
Summary:     Special coordinate handling for PPV FITS datasets. Allows the axes in PlotWindow to be labeled appropriately.
Affected #:  13 files

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/analysis_modules/halo_analysis/halo_finding_methods.py
--- a/yt/analysis_modules/halo_analysis/halo_finding_methods.py
+++ /dev/null
@@ -1,141 +0,0 @@
-"""
-Halo Finding methods
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-
-from yt.analysis_modules.halo_finding.halo_objects import \
-    FOFHaloFinder, HOPHaloFinder
-from yt.frontends.halo_catalogs.halo_catalog.data_structures import \
-    HaloCatalogDataset
-from yt.frontends.stream.data_structures import \
-    load_particles
-
-from .operator_registry import \
-    finding_method_registry
-
-
-def add_finding_method(name, function):
-    finding_method_registry[name] = HaloFindingMethod(function)
-    
-class HaloFindingMethod(object):
-    r"""
-    A halo finding method is a callback that performs halo finding on a 
-    dataset and returns a new dataset that is the loaded halo finder output.
-    """
-    def __init__(self, function, args=None, kwargs=None):
-        self.function = function
-        self.args = args
-        if self.args is None: self.args = []
-        self.kwargs = kwargs
-        if self.kwargs is None: self.kwargs = {}
-
-    def __call__(self, ds):
-        return self.function(ds, *self.args, **self.kwargs)
-
-def _hop_method(pf):
-    r"""
-    Run the Hop halo finding method.
-    """
-    
-    halo_list = HOPHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("hop", _hop_method)
-
-def _fof_method(pf):
-    r"""
-    Run the FoF halo finding method.
-    """
-
-    halo_list = FOFHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("fof", _fof_method)
-
-def _rockstar_method(pf):
-    r"""
-    Run the Rockstar halo finding method.
-    """
-
-    from yt.frontends.halo_catalogs.rockstar.data_structures import \
-     RockstarDataset
-    from yt.analysis_modules.halo_finding.rockstar.api import \
-     RockstarHaloFinder
-    
-    rh = RockstarHaloFinder(pf)
-    rh.run()
-
-
-    halos_pf = RockstarDataset("rockstar_halos/halos_0.0.bin")
-    try:
-        halos_pf.create_field_info()
-    except ValueError:
-        return None
-
-    return halos_pf
-add_finding_method("rockstar", _rockstar_method)
-
-def _parse_old_halo_list(data_pf, halo_list):
-    r"""
-    Convert the halo list into a loaded dataset.
-    """
-
-    num_halos = len(halo_list)
-
-    if num_halos == 0: return None
-
-    # Set up fields that we want to pull from identified halos and their units
-    new_fields = ['particle_identifier', 'particle_mass', 'particle_position_x', 
-        'particle_position_y','particle_position_z',
-        'virial_radius']
-    new_units = [ '', 'g', 'cm', 'cm','cm','cm']
-
-    # Set up a dictionary based on those fields 
-    # with empty arrays where we will fill in their values
-    halo_properties = { f : (np.zeros(num_halos),unit) \
-        for f, unit in zip(new_fields,new_units)}
-
-    # Iterate through the halos pulling out their positions and virial quantities
-    # and filling in the properties dictionary
-    for i,halo in enumerate(halo_list):
-        halo_properties['particle_identifier'][0][i] = i
-        halo_properties['particle_mass'][0][i] = halo.virial_mass().in_cgs()
-        halo_properties['virial_radius'][0][i] = halo.virial_radius().in_cgs()
-
-        com = halo.center_of_mass().in_cgs()
-        halo_properties['particle_position_x'][0][i] = com[0]
-        halo_properties['particle_position_y'][0][i] = com[1]
-        halo_properties['particle_position_z'][0][i] = com[2]
-
-    # Define a bounding box based on original data pf
-    bbox = np.array([data_pf.domain_left_edge.in_cgs(),
-            data_pf.domain_right_edge.in_cgs()]).T
-
-    # Create a pf with the halos as particles
-    particle_pf = load_particles(halo_properties, 
-            bbox=bbox, length_unit = 1, mass_unit=1)
-
-    # Create the field info dictionary so we can reference those fields
-    particle_pf.create_field_info()
-
-    for attr in ["current_redshift", "current_time",
-                 "domain_dimensions",
-                 "cosmological_simulation", "omega_lambda",
-                 "omega_matter", "hubble_constant"]:
-        attr_val = getattr(data_pf, attr)
-        setattr(particle_pf, attr, attr_val)
-    particle_pf.current_time = particle_pf.current_time.in_cgs()
-    
-    return particle_pf

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -54,6 +54,8 @@
     SphericalCoordinateHandler
 from yt.geometry.geographic_coordinates import \
     GeographicCoordinateHandler
+from yt.geometry.ppv_coordinates import \
+    PPVCoordinateHandler
 
 # We want to support the movie format in the future.
 # When such a thing comes to pass, I'll move all the stuff that is contant up
@@ -370,6 +372,8 @@
             self.coordinates = SphericalCoordinateHandler(self)
         elif self.geometry == "geographic":
             self.coordinates = GeographicCoordinateHandler(self)
+        elif self.geometry == "ppv":
+            self.coordinates = PPVCoordinateHandler(self)
         else:
             raise YTGeometryNotSupported(self.geometry)
 

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -508,6 +508,8 @@
     def _setup_ppv(self):
 
         self.ppv_data = True
+        self.geometry = "ppv"
+
         end = min(self.dimensionality+1,4)
         if self.events_data:
             ctypes = self.axis_names
@@ -550,7 +552,7 @@
             x0 = self.wcs.wcs.crpix[self.vel_axis]
             dz = self.wcs.wcs.cdelt[self.vel_axis]
             z0 = self.wcs.wcs.crval[self.vel_axis]
-            self.vunit = str(self.wcs.wcs.cunit[self.vel_axis])
+            self.vel_unit = str(self.wcs.wcs.cunit[self.vel_axis])
 
             self.domain_left_edge[self.vel_axis] = \
                 (self.domain_left_edge[self.vel_axis]-x0)*dz + z0
@@ -562,7 +564,7 @@
             self.wcs_2d = self.wcs
             self.vel_axis = 2
             self.vel_name = "z"
-            self.vunit = "code length"
+            self.vel_unit = "code length"
 
     def __del__(self):
         for file in self._fits_files:

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/frontends/fits/fields.py
--- a/yt/frontends/fits/fields.py
+++ b/yt/frontends/fits/fields.py
@@ -44,9 +44,9 @@
         if self.pf.dimensionality == 3:
             def _vel_los(field, data):
                 axis = "xyz"[data.pf.vel_axis]
-                return data.pf.arr(data[axis].ndarray_view(),data.pf.vunit)
-            self.add_field(("fits",data.pf.vel_name), function=_vel_los,
-                           units=data.pf.vunit)
+                return data.pf.arr(data[axis].ndarray_view(),data.pf.vel_unit)
+            self.add_field(("fits",self.pf.vel_name), function=_vel_los,
+                           units=self.pf.vel_unit)
 
     def setup_fluid_fields(self):
 

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/frontends/fits/setup.py
--- a/yt/frontends/fits/setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('fits', parent_package, top_path)
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/frontends/fits/tests/test_outputs.py
--- a/yt/frontends/fits/tests/test_outputs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-FITS frontend tests
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from yt.testing import *
-from yt.utilities.answer_testing.framework import \
-    requires_pf, \
-    small_patch_amr, \
-    big_patch_amr, \
-    data_dir_load
-
-_fields = ("intensity")
-
-m33 = "fits/m33_hi.fits"
- at requires_pf(m33, big_data=True)
-def test_m33():
-    pf = data_dir_load(m33)
-    yield assert_equal, str(pf), "m33_hi.fits"
-    for test in small_patch_amr(m33, _fields):
-        test_m33.__name__ = test.description
-        yield test
-
-_fields = ("x-velocity","y-velocity","z-velocity")
-
-vf = "fits/velocity_field_20.fits"
- at requires_pf(vf)
-def test_velocity_field():
-    pf = data_dir_load(bf)
-    yield assert_equal, str(pf), "velocity_field_20.fits"
-    for test in small_patch_amr(vf, _fields):
-        test_velocity_field.__name__ = test.description
-        yield test

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/geometry/ppv_coordinates.py
--- /dev/null
+++ b/yt/geometry/ppv_coordinates.py
@@ -0,0 +1,72 @@
+"""
+Cartesian fields
+
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+import numpy as np
+from .cartesian_coordinates import \
+    CartesianCoordinateHandler
+
+class PPVCoordinateHandler(CartesianCoordinateHandler):
+
+    def __init__(self, pf):
+        super(PPVCoordinateHandler, self).__init__(pf)
+
+        self.axis_name = {}
+        self.axis_id = {}
+        self.x_axis = {}
+        self.y_axis = {}
+
+        for axis, axis_name in zip([pf.lon_axis, pf.lat_axis, pf.vel_axis],
+                                   ["Image\ x", "Image\ y", pf.vel_name]):
+            lower_ax = "xyz"[axis]
+            upper_ax = lower_ax.upper()
+
+            self.axis_name[axis] = axis_name
+            self.axis_name[lower_ax] = axis_name
+            self.axis_name[upper_ax] = axis_name
+            self.axis_name[axis_name] = axis_name
+
+            self.axis_id[lower_ax] = axis
+            self.axis_id[axis] = axis
+            self.axis_id[axis_name] = axis
+
+            if axis == 0:
+                self.x_axis[axis] = 1
+                self.x_axis[lower_ax] = 1
+                self.x_axis[axis_name] = 1
+            else:
+                self.x_axis[axis] = 0
+                self.x_axis[lower_ax] = 0
+                self.x_axis[axis_name] = 0
+
+            if axis == 2:
+                self.y_axis[axis] = 1
+                self.y_axis[lower_ax] = 1
+                self.y_axis[axis_name] = 1
+            else:
+                self.y_axis[axis] = 2
+                self.y_axis[lower_ax] = 2
+                self.y_axis[axis_name] = 2
+
+        self.default_unit_label = {}
+        self.default_unit_label[pf.lon_axis] = "pixel"
+        self.default_unit_label[pf.lat_axis] = "pixel"
+        self.default_unit_label[pf.vel_axis] = pf.vel_unit
+
+    def convert_to_cylindrical(self, coord):
+        raise NotImplementedError
+
+    def convert_from_cylindrical(self, coord):
+        raise NotImplementedError

diff -r ad6c28383ac2cda76cf820efb0492b94f9af75d7 -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -161,7 +161,7 @@
     return center
 
 def get_window_parameters(axis, center, width, pf):
-    if pf.geometry == "cartesian":
+    if pf.geometry == "cartesian" or pf.geometry == "ppv":
         width = get_sanitized_width(axis, width, None, pf)
         center = get_sanitized_center(center, pf)
     elif pf.geometry in ("polar", "cylindrical"):
@@ -813,6 +813,11 @@
                 comoving = False
                 hinv = False
                 for i, un in enumerate((unit_x, unit_y)):
+                    if hasattr(self.pf.coordinates, "default_unit_label"):
+                        axax = getattr(self.pf.coordinates, "%s_axis" % ("xy"[i]))[axis_index]
+                        un = self.pf.coordinates.default_unit_label[axax]
+                        axes_unit_labels[i] = '\/\/('+un+')'
+                        continue
                     # Use sympy to factor h out of the unit.  In this context 'un'
                     # is a string, so we call the Unit constructor.
                     expr = Unit(un, registry=self.pf.unit_registry).expr
@@ -847,6 +852,9 @@
                     axis_names = self.pf.coordinates.axis_name
                     xax = self.pf.coordinates.x_axis[axis_index]
                     yax = self.pf.coordinates.y_axis[axis_index]
+                    if hasattr(self.pf.coordinates, "axis_default_unit_label"):
+                        axes_unit_labels = [self.pf.coordinates.axis_default_unit_name[xax],
+                                            self.pf.coordinates.axis_default_unit_name[yax]]
                     labels = [r'$\rm{'+axis_names[xax]+axes_unit_labels[0] + r'}$',
                               r'$\rm{'+axis_names[yax]+axes_unit_labels[1] + r'}$']
 


https://bitbucket.org/yt_analysis/yt/commits/8eb2f2efa6d3/
Changeset:   8eb2f2efa6d3
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-29 18:15:59
Summary:     Adding mul_symbol to make units in plots more readable. We may change this later.
Affected #:  10 files

diff -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 yt/analysis_modules/halo_analysis/halo_finding_methods.py
--- a/yt/analysis_modules/halo_analysis/halo_finding_methods.py
+++ /dev/null
@@ -1,141 +0,0 @@
-"""
-Halo Finding methods
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-
-from yt.analysis_modules.halo_finding.halo_objects import \
-    FOFHaloFinder, HOPHaloFinder
-from yt.frontends.halo_catalogs.halo_catalog.data_structures import \
-    HaloCatalogDataset
-from yt.frontends.stream.data_structures import \
-    load_particles
-
-from .operator_registry import \
-    finding_method_registry
-
-
-def add_finding_method(name, function):
-    finding_method_registry[name] = HaloFindingMethod(function)
-    
-class HaloFindingMethod(object):
-    r"""
-    A halo finding method is a callback that performs halo finding on a 
-    dataset and returns a new dataset that is the loaded halo finder output.
-    """
-    def __init__(self, function, args=None, kwargs=None):
-        self.function = function
-        self.args = args
-        if self.args is None: self.args = []
-        self.kwargs = kwargs
-        if self.kwargs is None: self.kwargs = {}
-
-    def __call__(self, ds):
-        return self.function(ds, *self.args, **self.kwargs)
-
-def _hop_method(pf):
-    r"""
-    Run the Hop halo finding method.
-    """
-    
-    halo_list = HOPHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("hop", _hop_method)
-
-def _fof_method(pf):
-    r"""
-    Run the FoF halo finding method.
-    """
-
-    halo_list = FOFHaloFinder(pf)
-    halos_pf = _parse_old_halo_list(pf, halo_list)
-    return halos_pf
-add_finding_method("fof", _fof_method)
-
-def _rockstar_method(pf):
-    r"""
-    Run the Rockstar halo finding method.
-    """
-
-    from yt.frontends.halo_catalogs.rockstar.data_structures import \
-     RockstarDataset
-    from yt.analysis_modules.halo_finding.rockstar.api import \
-     RockstarHaloFinder
-    
-    rh = RockstarHaloFinder(pf)
-    rh.run()
-
-
-    halos_pf = RockstarDataset("rockstar_halos/halos_0.0.bin")
-    try:
-        halos_pf.create_field_info()
-    except ValueError:
-        return None
-
-    return halos_pf
-add_finding_method("rockstar", _rockstar_method)
-
-def _parse_old_halo_list(data_pf, halo_list):
-    r"""
-    Convert the halo list into a loaded dataset.
-    """
-
-    num_halos = len(halo_list)
-
-    if num_halos == 0: return None
-
-    # Set up fields that we want to pull from identified halos and their units
-    new_fields = ['particle_identifier', 'particle_mass', 'particle_position_x', 
-        'particle_position_y','particle_position_z',
-        'virial_radius']
-    new_units = [ '', 'g', 'cm', 'cm','cm','cm']
-
-    # Set up a dictionary based on those fields 
-    # with empty arrays where we will fill in their values
-    halo_properties = { f : (np.zeros(num_halos),unit) \
-        for f, unit in zip(new_fields,new_units)}
-
-    # Iterate through the halos pulling out their positions and virial quantities
-    # and filling in the properties dictionary
-    for i,halo in enumerate(halo_list):
-        halo_properties['particle_identifier'][0][i] = i
-        halo_properties['particle_mass'][0][i] = halo.virial_mass().in_cgs()
-        halo_properties['virial_radius'][0][i] = halo.virial_radius().in_cgs()
-
-        com = halo.center_of_mass().in_cgs()
-        halo_properties['particle_position_x'][0][i] = com[0]
-        halo_properties['particle_position_y'][0][i] = com[1]
-        halo_properties['particle_position_z'][0][i] = com[2]
-
-    # Define a bounding box based on original data pf
-    bbox = np.array([data_pf.domain_left_edge.in_cgs(),
-            data_pf.domain_right_edge.in_cgs()]).T
-
-    # Create a pf with the halos as particles
-    particle_pf = load_particles(halo_properties, 
-            bbox=bbox, length_unit = 1, mass_unit=1)
-
-    # Create the field info dictionary so we can reference those fields
-    particle_pf.create_field_info()
-
-    for attr in ["current_redshift", "current_time",
-                 "domain_dimensions",
-                 "cosmological_simulation", "omega_lambda",
-                 "omega_matter", "hubble_constant"]:
-        attr_val = getattr(data_pf, attr)
-        setattr(particle_pf, attr, attr_val)
-    particle_pf.current_time = particle_pf.current_time.in_cgs()
-    
-    return particle_pf

diff -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 yt/frontends/fits/setup.py
--- a/yt/frontends/fits/setup.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('fits', parent_package, top_path)
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 yt/frontends/fits/tests/test_outputs.py
--- a/yt/frontends/fits/tests/test_outputs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-FITS frontend tests
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from yt.testing import *
-from yt.utilities.answer_testing.framework import \
-    requires_pf, \
-    small_patch_amr, \
-    big_patch_amr, \
-    data_dir_load
-
-_fields = ("intensity")
-
-m33 = "fits/m33_hi.fits"
- at requires_pf(m33, big_data=True)
-def test_m33():
-    pf = data_dir_load(m33)
-    yield assert_equal, str(pf), "m33_hi.fits"
-    for test in small_patch_amr(m33, _fields):
-        test_m33.__name__ = test.description
-        yield test
-
-_fields = ("x-velocity","y-velocity","z-velocity")
-
-vf = "fits/velocity_field_20.fits"
- at requires_pf(vf)
-def test_velocity_field():
-    pf = data_dir_load(bf)
-    yield assert_equal, str(pf), "velocity_field_20.fits"
-    for test in small_patch_amr(vf, _fields):
-        test_velocity_field.__name__ = test.description
-        yield test

diff -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 yt/geometry/ppv_coordinates.py
--- a/yt/geometry/ppv_coordinates.py
+++ /dev/null
@@ -1,72 +0,0 @@
-"""
-Cartesian fields
-
-
-
-
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from .cartesian_coordinates import \
-    CartesianCoordinateHandler
-
-class PPVCoordinateHandler(CartesianCoordinateHandler):
-
-    def __init__(self, pf):
-        super(PPVCoordinateHandler, self).__init__(pf)
-
-        self.axis_name = {}
-        self.axis_id = {}
-        self.x_axis = {}
-        self.y_axis = {}
-
-        for axis, axis_name in zip([pf.lon_axis, pf.lat_axis, pf.vel_axis],
-                                   ["Image\ x", "Image\ y", pf.vel_name]):
-            lower_ax = "xyz"[axis]
-            upper_ax = lower_ax.upper()
-
-            self.axis_name[axis] = axis_name
-            self.axis_name[lower_ax] = axis_name
-            self.axis_name[upper_ax] = axis_name
-            self.axis_name[axis_name] = axis_name
-
-            self.axis_id[lower_ax] = axis
-            self.axis_id[axis] = axis
-            self.axis_id[axis_name] = axis
-
-            if axis == 0:
-                self.x_axis[axis] = 1
-                self.x_axis[lower_ax] = 1
-                self.x_axis[axis_name] = 1
-            else:
-                self.x_axis[axis] = 0
-                self.x_axis[lower_ax] = 0
-                self.x_axis[axis_name] = 0
-
-            if axis == 2:
-                self.y_axis[axis] = 1
-                self.y_axis[lower_ax] = 1
-                self.y_axis[axis_name] = 1
-            else:
-                self.y_axis[axis] = 2
-                self.y_axis[lower_ax] = 2
-                self.y_axis[axis_name] = 2
-
-        self.default_unit_label = {}
-        self.default_unit_label[pf.lon_axis] = "pixel"
-        self.default_unit_label[pf.lat_axis] = "pixel"
-        self.default_unit_label[pf.vel_axis] = pf.vel_unit
-
-    def convert_to_cylindrical(self, coord):
-        raise NotImplementedError
-
-    def convert_from_cylindrical(self, coord):
-        raise NotImplementedError

diff -r 45b7456c9d9822cbc6641ba46fb177e01b9092d4 -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 yt/units/unit_object.py
--- a/yt/units/unit_object.py
+++ b/yt/units/unit_object.py
@@ -358,7 +358,8 @@
         for ex in self.expr.free_symbols:
             symbol_table[ex] = latex_symbol_lut[str(ex)]
         return latex(self.expr, symbol_names=symbol_table,
-                     fold_frac_powers=True, fold_short_frac=True)
+                     mul_symbol="dot", fold_frac_powers=True,
+                     fold_short_frac=True)
 #
 # Unit manipulation functions
 #


https://bitbucket.org/yt_analysis/yt/commits/6694fd1ba4dc/
Changeset:   6694fd1ba4dc
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-29 18:21:34
Summary:     Merge
Affected #:  10 files

diff -r 8eb2f2efa6d35724da3bf2c532edda36e3cc8ab3 -r 6694fd1ba4dce6dcb3a9edc24c2a81636d31cf82 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -121,6 +121,7 @@
     def _guess_name_from_units(self, units):
         for k,v in field_from_unit.items():
             if k in units:
+                mylog.warning("Guessing this is a %s field based on its units of %s." % (v,k))
                 return v
         return None
 


https://bitbucket.org/yt_analysis/yt/commits/aa53c0e6c3d8/
Changeset:   aa53c0e6c3d8
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-29 18:27:26
Summary:     Bug fixes
Affected #:  10 files

diff -r 6694fd1ba4dce6dcb3a9edc24c2a81636d31cf82 -r aa53c0e6c3d89551ac89d3c9c974f641ef0bc0c2 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -869,23 +869,22 @@
 
             else:
 
-                axis = self.data_source.axis
                 wcs_axes = self.plots[f].figure.axes[-1]
                 wcs = wcs_axes.wcs.wcs
                 self.plots[f].axes.get_xaxis().set_visible(False)
                 self.plots[f].axes.get_yaxis().set_visible(False)
-                xlabel = "%s (%s)" % (wcs.ctype[x_dict[axis]].split("-")[0],
-                                      wcs.cunit[x_dict[axis]])
-                ylabel = "%s (%s)" % (wcs.ctype[y_dict[axis]].split("-")[0],
-                                      wcs.cunit[x_dict[axis]])
+                xax = self.pf.coordinates.x_axis[axis_index]
+                yax = self.pf.coordinates.y_axis[axis_index]
+                xlabel = "%s (%s)" % (wcs.ctype[xax].split("-")[0],
+                                      wcs.cunit[xax])
+                ylabel = "%s (%s)" % (wcs.ctype[yax].split("-")[0],
+                                      wcs.cunit[yax])
                 wcs_axes.coords[0].set_axislabel(xlabel, fontproperties=fp)
                 wcs_axes.coords[1].set_axislabel(ylabel, fontproperties=fp)
                 wcs_axes.set_xlim(self.xlim[0].value, self.xlim[1].value)
                 wcs_axes.set_ylim(self.ylim[0].value, self.ylim[1].value)
                 wcs_axes.coords[0].ticklabels.set_fontproperties(fp)
                 wcs_axes.coords[1].ticklabels.set_fontproperties(fp)
-                wcs_axes.coords[0].set_major_formatter('d.dd')
-                wcs_axes.coords[1].set_major_formatter('d.dd')
 
             colorbar_label = image.info['label']
 


https://bitbucket.org/yt_analysis/yt/commits/4ae52a632a9f/
Changeset:   4ae52a632a9f
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 13:45:23
Summary:     More flexibility in specifying figure sizes and aspects. Defaults remain the same.
Affected #:  3 files

diff -r aa53c0e6c3d89551ac89d3c9c974f641ef0bc0c2 -r 4ae52a632a9f4ecc4e60f41e75f153243b5d18b9 yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -17,7 +17,7 @@
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \
-    get_image_suffix, mylog
+    get_image_suffix, mylog, iterable
 import numpy as np
 
 class CallbackWrapper(object):
@@ -140,12 +140,16 @@
             top_buff_size = 0.0
 
         # Ensure the figure size along the long axis is always equal to _figure_size
-        if self._aspect >= 1.0:
-            x_fig_size = self._figure_size
-            y_fig_size = self._figure_size/self._aspect
-        if self._aspect < 1.0:
-            x_fig_size = self._figure_size*self._aspect
-            y_fig_size = self._figure_size
+        if iterable(self._figure_size):
+            x_fig_size = self._figure_size[0]
+            y_fig_size = self._figure_size[1]
+        else:
+            if self._aspect >= 1.0:
+                x_fig_size = self._figure_size
+                y_fig_size = self._figure_size/self._aspect
+            if self._aspect < 1.0:
+                x_fig_size = self._figure_size*self._aspect
+                y_fig_size = self._figure_size
 
         xbins = np.array([x_axis_size, x_fig_size, cb_size, cb_text_size])
         ybins = np.array([y_axis_size, y_fig_size, top_buff_size])

diff -r aa53c0e6c3d89551ac89d3c9c974f641ef0bc0c2 -r 4ae52a632a9f4ecc4e60f41e75f153243b5d18b9 yt/visualization/plot_container.py
--- a/yt/visualization/plot_container.py
+++ b/yt/visualization/plot_container.py
@@ -16,7 +16,7 @@
 
 from yt.funcs import \
     defaultdict, get_image_suffix, \
-    get_ipython_api_version
+    get_ipython_api_version, iterable
 from yt.utilities.exceptions import \
     YTNotInsideNotebook
 from ._mpl_imports import FigureCanvasAgg
@@ -111,7 +111,10 @@
 
     def __init__(self, data_source, figure_size, fontsize):
         self.data_source = data_source
-        self.figure_size = float(figure_size)
+        if iterable(figure_size):
+            self.figure_size = float(figure_size[0]), float(figure_size[1])
+        else:
+            self.figure_size = float(figure_size)
         self.plots = PlotDictionary(data_source)
         self._callbacks = []
         self._field_transform = {}

diff -r aa53c0e6c3d89551ac89d3c9c974f641ef0bc0c2 -r 4ae52a632a9f4ecc4e60f41e75f153243b5d18b9 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -269,7 +269,7 @@
     _frb = None
     def __init__(self, data_source, bounds, buff_size=(800,800), antialias=True,
                  periodic=True, origin='center-window', oblique=False,
-                 window_size=8.0, fields=None, fontsize=18, setup=False):
+                 window_size=8.0, fields=None, fontsize=18, aspect=None, setup=False):
         if not hasattr(self, "pf"):
             self.pf = data_source.pf
             ts = self._initialize_dataset(self.pf)
@@ -282,6 +282,7 @@
         self.oblique = oblique
         self.buff_size = buff_size
         self.antialias = antialias
+        self.aspect = aspect
         skip = list(FixedResolutionBuffer._exclude_fields) + data_source._key_fields
         if fields is None:
             fields = []
@@ -762,7 +763,12 @@
             else:
                 (unit_x, unit_y) = self._axes_unit_names
 
-            aspect = np.float64(self.pf.quan(1.0, unit_y)/self.pf.quan(1.0, unit_x))
+            dds = self.pf.index.select_grids(self.pf.index.grid_levels.max())[0].dds[:]
+            xax = self.pf.coordinates.x_axis[axis_index]
+            yax = self.pf.coordinates.y_axis[axis_index]
+
+            if self.aspect is None:
+                self.aspect = np.float64(self.pf.quan(1.0, unit_y)/(self.pf.quan(1.0, unit_x)))
 
             extentx = [(self.xlim[i] - xc).in_units(unit_x) for i in (0, 1)]
             extenty = [(self.ylim[i] - yc).in_units(unit_y) for i in (0, 1)]
@@ -803,7 +809,7 @@
                 image, self._field_transform[f].name,
                 self._colormaps[f], extent, zlim,
                 self.figure_size, fp.get_size(),
-                aspect, fig, axes, cax)
+                self.aspect, fig, axes, cax)
 
             if not hasattr(self.plots[f].figure.axes[-1], "wcs"):
                 self._wcs_axes = False
@@ -1051,7 +1057,7 @@
     _frb_generator = FixedResolutionBuffer
 
     def __init__(self, pf, axis, fields, center='c', width=None, axes_unit=None,
-                 origin='center-window', fontsize=18, field_parameters=None):
+                 origin='center-window', fontsize=18, field_parameters=None, **kwargs):
         # this will handle time series data and controllers
         ts = self._initialize_dataset(pf)
         self.ts = ts
@@ -1063,7 +1069,7 @@
             field_parameters = field_parameters, center=center)
         slc.get_data(fields)
         PWViewerMPL.__init__(self, slc, bounds, origin=origin,
-                             fontsize=fontsize, fields=fields)
+                             fontsize=fontsize, fields=fields, **kwargs)
         if axes_unit is None:
             axes_unit = get_axes_unit(width, pf)
         self.set_axes_unit(axes_unit)
@@ -1662,7 +1668,11 @@
         if fontscale < 1.0:
             fontscale = np.sqrt(fontscale)
 
-        self._cb_size = 0.0375*figure_size
+        if iterable(figure_size):
+            fsize = figure_size[0]
+        else:
+            fsize = figure_size
+        self._cb_size = 0.0375*fsize
         self._ax_text_size = [0.9*fontscale, 0.7*fontscale]
         self._top_buff_size = 0.30*fontscale
         self._aspect = ((extent[1] - extent[0])/(extent[3] - extent[2]))


https://bitbucket.org/yt_analysis/yt/commits/93b630cbfde6/
Changeset:   93b630cbfde6
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 15:16:33
Summary:     Adjust axes extents for WCS coordinates
Affected #:  1 file

diff -r 4ae52a632a9f4ecc4e60f41e75f153243b5d18b9 -r 93b630cbfde6ef6d8fe775c3f728be143bb8c164 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -626,7 +626,7 @@
         Examples
         --------
 
-        >>> p = ProjectionPlot(pf, "y", "Density")
+        >>> p = ProjectionPlot(pf, "y", "density")
         >>> p.show()
         >>> p.set_axes_unit("kpc")
         >>> p.show()
@@ -658,6 +658,9 @@
         if set_axes and not self._wcs_axes:
             self._wcs_axes = True
             for f in self.plots:
+                # These will get reset later
+                self.plots[f]._ax_text_size[0] *= 1.55
+                self.plots[f]._ax_text_size[1] *= 1.14
                 rect = self.plots[f]._get_best_layout()[1]
                 fig = self.plots[f].figure
                 ax = WCSAxes(fig, rect, wcs=self.pf.wcs_2d, frameon=False)
@@ -809,7 +812,7 @@
                 image, self._field_transform[f].name,
                 self._colormaps[f], extent, zlim,
                 self.figure_size, fp.get_size(),
-                self.aspect, fig, axes, cax)
+                self.aspect, fig, axes, cax, self._wcs_axes)
 
             if not hasattr(self.plots[f].figure.axes[-1], "wcs"):
                 self._wcs_axes = False
@@ -1184,7 +1187,7 @@
     def __init__(self, pf, axis, fields, center='c', width=None, axes_unit=None,
                  weight_field=None, max_level=None, origin='center-window',
                  fontsize=18, field_parameters=None, data_source=None,
-                 proj_style = "integrate"):
+                 proj_style = "integrate", **kwargs):
         ts = self._initialize_dataset(pf)
         self.ts = ts
         pf = self.pf = ts[0]
@@ -1195,7 +1198,7 @@
                          center=center, data_source=data_source,
                          field_parameters = field_parameters, style = proj_style)
         PWViewerMPL.__init__(self, proj, bounds, fields=fields, origin=origin,
-                             fontsize=fontsize)
+                             fontsize=fontsize, **kwargs)
         if axes_unit is None:
             axes_unit = get_axes_unit(width, pf)
         self.set_axes_unit(axes_unit)
@@ -1657,7 +1660,7 @@
 
 class WindowPlotMPL(ImagePlotMPL):
     def __init__(self, data, cbname, cmap, extent, zlim, figure_size, fontsize,
-                 unit_aspect, figure, axes, cax):
+                 unit_aspect, figure, axes, cax, wcs_axes=False):
         self._draw_colorbar = True
         self._draw_axes = True
         self._fontsize = fontsize
@@ -1674,6 +1677,10 @@
             fsize = figure_size
         self._cb_size = 0.0375*fsize
         self._ax_text_size = [0.9*fontscale, 0.7*fontscale]
+        if wcs_axes:
+            # Add a bit more space for the WCS coordinates
+            self._ax_text_size[0] *= 1.55
+            self._ax_text_size[1] *= 1.14
         self._top_buff_size = 0.30*fontscale
         self._aspect = ((extent[1] - extent[0])/(extent[3] - extent[2]))
 


https://bitbucket.org/yt_analysis/yt/commits/b304b6233a35/
Changeset:   b304b6233a35
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 15:24:49
Summary:     Give access to the axes instance so that its parameters can be adjusted.
Affected #:  1 file

diff -r 93b630cbfde6ef6d8fe775c3f728be143bb8c164 -r b304b6233a354bb9eb6c3f94d7fbcee30b367886 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -647,7 +647,17 @@
 
     @invalidate_data
     @invalidate_plot
-    def set_wcs_axes(self, set_axes):
+    def set_wcs_axes(self, set_axes, wcs_axes=None):
+        r"""
+        Use the wcsaxes library to plot celestial coordinates on the axes.
+
+        Parameters
+        ----------
+        set_axes : boolean
+            Turn on or off the WCS axes.
+        wcs_axes : WCSAxes instance
+            The WCSAxes instance, for adjusting the axes properties
+        """
         from wcsaxes import WCSAxes
         if self.oblique:
             raise NotImplementedError("WCS axes are not implemented for oblique plots.")
@@ -665,6 +675,7 @@
                 fig = self.plots[f].figure
                 ax = WCSAxes(fig, rect, wcs=self.pf.wcs_2d, frameon=False)
                 fig.add_axes(ax)
+                if wcs_axes is not None: wcs_axes=ax
         else:
             if not self._wcs_axes: return self
             self._wcs_axes = False


https://bitbucket.org/yt_analysis/yt/commits/e2d25a09e796/
Changeset:   e2d25a09e796
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 15:27:16
Summary:     Bit more info
Affected #:  1 file

diff -r b304b6233a354bb9eb6c3f94d7fbcee30b367886 -r e2d25a09e796c411e6caadd73b809b6095a3f345 yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -656,7 +656,8 @@
         set_axes : boolean
             Turn on or off the WCS axes.
         wcs_axes : WCSAxes instance
-            The WCSAxes instance, for adjusting the axes properties
+            The WCSAxes instance, for adjusting the axes properties. See
+            http://wcsaxes.readthedocs.org for details.
         """
         from wcsaxes import WCSAxes
         if self.oblique:


https://bitbucket.org/yt_analysis/yt/commits/a42fc3ad5450/
Changeset:   a42fc3ad5450
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 17:16:28
Summary:     cut regions from ds9 regions
Affected #:  1 file

diff -r e2d25a09e796c411e6caadd73b809b6095a3f345 -r a42fc3ad5450574451468f0beb4553e8e1db13bf yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -14,6 +14,7 @@
 from yt.fields.api import add_field
 from yt.fields.derived_field import ValidateSpatial
 from yt.funcs import mylog
+import os
 
 def _make_counts(emin, emax):
     def _counts(field, data):
@@ -35,4 +36,22 @@
         add_field(("gas",fname), function=cfunc,
                   units="counts/pixel",
                   validators = [ValidateSpatial()],
-                  display_name="Counts (%s-%s keV)" % (emin, emax))
\ No newline at end of file
+                  display_name="Counts (%s-%s keV)" % (emin, emax))
+
+def ds9_region(ds, reg, obj=None):
+    import pyregion
+    r = pyregion.open(reg)
+    reg_name = reg.split(".")[0]
+    mask = r.get_mask(hdu=ds._handle[ds.first_image])
+    def _reg_field(field, data):
+        i = data["x"].ndarray_view().astype("int")-1
+        j = data["y"].ndarray_view().astype("int")-1
+        new_mask = mask[i,j]
+        ret = data["zeros"].copy()
+        ret[new_mask] = 1.
+        return ret
+    ds.index
+    ds.field_info.add_field(("gas",reg_name), function=_reg_field)
+    if obj is None:
+        obj = ds.all_data()
+    return obj.cut_region(["obj['%s'] > 0" % (reg_name)])
\ No newline at end of file


https://bitbucket.org/yt_analysis/yt/commits/8994e12b9f95/
Changeset:   8994e12b9f95
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 17:46:14
Summary:     Better handling of the mask for 3D cubes and events files
Affected #:  1 file

diff -r a42fc3ad5450574451468f0beb4553e8e1db13bf -r 8994e12b9f95c618e003b818e061b43c1f8c2117 yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -42,7 +42,10 @@
     import pyregion
     r = pyregion.open(reg)
     reg_name = reg.split(".")[0]
-    mask = r.get_mask(hdu=ds._handle[ds.first_image])
+    nx = ds.domain_dimensions[ds.lon_axis]
+    ny = ds.domain_dimensions[ds.lat_axis]
+    mask = r.get_mask(header=ds.wcs_2d.to_header(),
+                      shape=[nx,ny])
     def _reg_field(field, data):
         i = data["x"].ndarray_view().astype("int")-1
         j = data["y"].ndarray_view().astype("int")-1


https://bitbucket.org/yt_analysis/yt/commits/c5e0902f5ba6/
Changeset:   c5e0902f5ba6
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 19:05:52
Summary:     Successfully split the wcs_axes stuff into a separate class this is FITS-only. Much better than cluttering up PlotWindow.
Affected #:  2 files

diff -r 8994e12b9f95c618e003b818e061b43c1f8c2117 -r c5e0902f5ba691a5f4f31597673e2d5a0a11206f yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -13,7 +13,8 @@
 import numpy as np
 from yt.fields.api import add_field
 from yt.fields.derived_field import ValidateSpatial
-from yt.funcs import mylog
+from yt.funcs import mylog, get_image_suffix
+from yt.visualization._mpl_imports import FigureCanvasAgg
 import os
 
 def _make_counts(emin, emax):
@@ -57,4 +58,76 @@
     ds.field_info.add_field(("gas",reg_name), function=_reg_field)
     if obj is None:
         obj = ds.all_data()
-    return obj.cut_region(["obj['%s'] > 0" % (reg_name)])
\ No newline at end of file
+    return obj.cut_region(["obj['%s'] > 0" % (reg_name)])
+
+class PlotWindowWCS(object):
+    r"""
+    Use the wcsaxes library to plot celestial coordinates on the axes.
+
+    Parameters
+    ----------
+    set_axes : boolean
+        Turn on or off the WCS axes.
+    wcs_axes : WCSAxes instance
+        The WCSAxes instance, for adjusting the axes properties. See
+        http://wcsaxes.readthedocs.org for details.
+    """
+    def __init__(self, pw):
+        from wcsaxes import WCSAxes
+        if pw.oblique:
+            raise NotImplementedError("WCS axes are not implemented for oblique plots.")
+        if not hasattr(pw.pf, "wcs_2d"):
+            raise NotImplementedError("WCS axes are not implemented for this dataset.")
+        if pw.data_source.axis != pw.pf.vel_axis:
+            raise NotImplementedError("WCS axes are not implemented for this axis.")
+        self.plots = {}
+        for f in pw.plots:
+            rect = pw.plots[f]._get_best_layout()[1]
+            fig = pw.plots[f].figure
+            ax = WCSAxes(fig, rect, wcs=pw.pf.wcs_2d, frameon=False)
+            fig.add_axes(ax)
+            wcs = ax.wcs.wcs
+            pw.plots[f].axes.get_xaxis().set_visible(False)
+            pw.plots[f].axes.get_yaxis().set_visible(False)
+            xax = pw.pf.coordinates.x_axis[pw.data_source.axis]
+            yax = pw.pf.coordinates.y_axis[pw.data_source.axis]
+            xlabel = "%s (%s)" % (wcs.ctype[xax].split("-")[0],
+                                  wcs.cunit[xax])
+            ylabel = "%s (%s)" % (wcs.ctype[yax].split("-")[0],
+                                  wcs.cunit[yax])
+            fp = pw._font_properties
+            ax.coords[0].set_axislabel(xlabel, fontproperties=fp)
+            ax.coords[1].set_axislabel(ylabel, fontproperties=fp)
+            ax.set_xlim(pw.xlim[0].value, pw.xlim[1].value)
+            ax.set_ylim(pw.ylim[0].value, pw.ylim[1].value)
+            ax.coords[0].ticklabels.set_fontproperties(fp)
+            ax.coords[1].ticklabels.set_fontproperties(fp)
+            self.plots[f] = pw.plots[f]
+        self.pw = pw
+        self.pf = self.pw.pf
+
+    def keys(self):
+        return self.plots.keys()
+
+    def values(self):
+        return self.plots.values()
+
+    def items(self):
+        return self.plots.items()
+
+    def __getitem__(self, key):
+        for k in self.keys():
+            if k[1] == key:
+                return self.plots[k]
+
+    def show(self):
+        from IPython.core.display import display
+        for k, v in sorted(self.plots.iteritems()):
+            canvas = FigureCanvasAgg(v.figure)
+            display(v.figure)
+
+    def save(self, name=None, mpl_kwargs=None):
+        if mpl_kwargs is None:
+            mpl_kwargs = {}
+        mpl_kwargs["bbox_inches"] = "tight"
+        self.pw.save(name=name, mpl_kwargs=mpl_kwargs)

diff -r 8994e12b9f95c618e003b818e061b43c1f8c2117 -r c5e0902f5ba691a5f4f31597673e2d5a0a11206f yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -277,7 +277,6 @@
         self._initfinished = False
         self._axes_unit_names = None
         self.center = None
-        self._wcs_axes = False
         self._periodic = periodic
         self.oblique = oblique
         self.buff_size = buff_size
@@ -645,48 +644,6 @@
         self._axes_unit_names = unit_name
         return self
 
-    @invalidate_data
-    @invalidate_plot
-    def set_wcs_axes(self, set_axes, wcs_axes=None):
-        r"""
-        Use the wcsaxes library to plot celestial coordinates on the axes.
-
-        Parameters
-        ----------
-        set_axes : boolean
-            Turn on or off the WCS axes.
-        wcs_axes : WCSAxes instance
-            The WCSAxes instance, for adjusting the axes properties. See
-            http://wcsaxes.readthedocs.org for details.
-        """
-        from wcsaxes import WCSAxes
-        if self.oblique:
-            raise NotImplementedError("WCS axes are not implemented for oblique plots.")
-        if not hasattr(self.pf, "wcs_2d"):
-            raise NotImplementedError("WCS axes are not implemented for this dataset.")
-        if self.data_source.axis != self.pf.vel_axis:
-            raise NotImplementedError("WCS axes are not implemented for this axis.")
-        if set_axes and not self._wcs_axes:
-            self._wcs_axes = True
-            for f in self.plots:
-                # These will get reset later
-                self.plots[f]._ax_text_size[0] *= 1.55
-                self.plots[f]._ax_text_size[1] *= 1.14
-                rect = self.plots[f]._get_best_layout()[1]
-                fig = self.plots[f].figure
-                ax = WCSAxes(fig, rect, wcs=self.pf.wcs_2d, frameon=False)
-                fig.add_axes(ax)
-                if wcs_axes is not None: wcs_axes=ax
-        else:
-            if not self._wcs_axes: return self
-            self._wcs_axes = False
-            for f in self.plots:
-                self.plots[f].figure = None
-                self.plots[f].axes = None
-                self.plots[f].cax = None
-            self._setup_plots()
-        return self
-
 class PWViewerMPL(PlotWindow):
     """Viewer using matplotlib as a backend via the WindowPlotMPL.
 
@@ -778,10 +735,6 @@
             else:
                 (unit_x, unit_y) = self._axes_unit_names
 
-            dds = self.pf.index.select_grids(self.pf.index.grid_levels.max())[0].dds[:]
-            xax = self.pf.coordinates.x_axis[axis_index]
-            yax = self.pf.coordinates.y_axis[axis_index]
-
             if self.aspect is None:
                 self.aspect = np.float64(self.pf.quan(1.0, unit_y)/(self.pf.quan(1.0, unit_x)))
 
@@ -824,88 +777,65 @@
                 image, self._field_transform[f].name,
                 self._colormaps[f], extent, zlim,
                 self.figure_size, fp.get_size(),
-                self.aspect, fig, axes, cax, self._wcs_axes)
+                self.aspect, fig, axes, cax)
 
-            if not hasattr(self.plots[f].figure.axes[-1], "wcs"):
-                self._wcs_axes = False
+            axes_unit_labels = ['', '']
+            comoving = False
+            hinv = False
+            for i, un in enumerate((unit_x, unit_y)):
+                if hasattr(self.pf.coordinates, "default_unit_label"):
+                    axax = getattr(self.pf.coordinates, "%s_axis" % ("xy"[i]))[axis_index]
+                    un = self.pf.coordinates.default_unit_label[axax]
+                    axes_unit_labels[i] = '\/\/('+un+')'
+                    continue
+                # Use sympy to factor h out of the unit.  In this context 'un'
+                # is a string, so we call the Unit constructor.
+                expr = Unit(un, registry=self.pf.unit_registry).expr
+                h_expr = Unit('h', registry=self.pf.unit_registry).expr
+                # See http://docs.sympy.org/latest/modules/core.html#sympy.core.expr.Expr
+                h_power = expr.as_coeff_exponent(h_expr)[1]
+                # un is now the original unit, but with h factored out.
+                un = str(expr*h_expr**(-1*h_power))
+                if str(un).endswith('cm') and un != 'cm':
+                    comoving = True
+                    un = un[:-2]
+                # no length units besides code_length end in h so this is safe
+                if h_power == -1:
+                    hinv = True
+                elif h_power != 0:
+                    # It doesn't make sense to scale a position by anything
+                    # other than h**-1
+                    raise RuntimeError
+                if un in formatted_length_unit_names:
+                    un = formatted_length_unit_names[un]
+                if un not in ['1', 'u', 'unitary']:
+                    if hinv:
+                        un = un + '\,h^{-1}'
+                    if comoving:
+                        un = un + '\,(1+z)^{-1}'
+                    axes_unit_labels[i] = '\/\/('+un+')'
 
-            if not self._wcs_axes:
-                axes_unit_labels = ['', '']
-                comoving = False
-                hinv = False
-                for i, un in enumerate((unit_x, unit_y)):
-                    if hasattr(self.pf.coordinates, "default_unit_label"):
-                        axax = getattr(self.pf.coordinates, "%s_axis" % ("xy"[i]))[axis_index]
-                        un = self.pf.coordinates.default_unit_label[axax]
-                        axes_unit_labels[i] = '\/\/('+un+')'
-                        continue
-                    # Use sympy to factor h out of the unit.  In this context 'un'
-                    # is a string, so we call the Unit constructor.
-                    expr = Unit(un, registry=self.pf.unit_registry).expr
-                    h_expr = Unit('h', registry=self.pf.unit_registry).expr
-                    # See http://docs.sympy.org/latest/modules/core.html#sympy.core.expr.Expr
-                    h_power = expr.as_coeff_exponent(h_expr)[1]
-                    # un is now the original unit, but with h factored out.
-                    un = str(expr*h_expr**(-1*h_power))
-                    if str(un).endswith('cm') and un != 'cm':
-                        comoving = True
-                        un = un[:-2]
-                    # no length units besides code_length end in h so this is safe
-                    if h_power == -1:
-                        hinv = True
-                    elif h_power != 0:
-                        # It doesn't make sense to scale a position by anything
-                        # other than h**-1
-                        raise RuntimeError
-                    if un in formatted_length_unit_names:
-                        un = formatted_length_unit_names[un]
-                    if un not in ['1', 'u', 'unitary']:
-                        if hinv:
-                            un = un + '\,h^{-1}'
-                        if comoving:
-                            un = un + '\,(1+z)^{-1}'
-                        axes_unit_labels[i] = '\/\/('+un+')'
-
-                if self.oblique:
-                    labels = [r'$\rm{Image\/x'+axes_unit_labels[0]+'}$',
-                              r'$\rm{Image\/y'+axes_unit_labels[1]+'}$']
-                else:
-                    axis_names = self.pf.coordinates.axis_name
-                    xax = self.pf.coordinates.x_axis[axis_index]
-                    yax = self.pf.coordinates.y_axis[axis_index]
-                    if hasattr(self.pf.coordinates, "axis_default_unit_label"):
-                        axes_unit_labels = [self.pf.coordinates.axis_default_unit_name[xax],
-                                            self.pf.coordinates.axis_default_unit_name[yax]]
-                    labels = [r'$\rm{'+axis_names[xax]+axes_unit_labels[0] + r'}$',
-                              r'$\rm{'+axis_names[yax]+axes_unit_labels[1] + r'}$']
-
-                self.plots[f].axes.set_xlabel(labels[0],fontproperties=fp)
-                self.plots[f].axes.set_ylabel(labels[1],fontproperties=fp)
-
-                for label in (self.plots[f].axes.get_xticklabels() +
-                              self.plots[f].axes.get_yticklabels() +
-                              [self.plots[f].axes.xaxis.get_offset_text(),
-                               self.plots[f].axes.yaxis.get_offset_text()]):
-                    label.set_fontproperties(fp)
-
+            if self.oblique:
+                labels = [r'$\rm{Image\/x'+axes_unit_labels[0]+'}$',
+                          r'$\rm{Image\/y'+axes_unit_labels[1]+'}$']
             else:
-
-                wcs_axes = self.plots[f].figure.axes[-1]
-                wcs = wcs_axes.wcs.wcs
-                self.plots[f].axes.get_xaxis().set_visible(False)
-                self.plots[f].axes.get_yaxis().set_visible(False)
+                axis_names = self.pf.coordinates.axis_name
                 xax = self.pf.coordinates.x_axis[axis_index]
                 yax = self.pf.coordinates.y_axis[axis_index]
-                xlabel = "%s (%s)" % (wcs.ctype[xax].split("-")[0],
-                                      wcs.cunit[xax])
-                ylabel = "%s (%s)" % (wcs.ctype[yax].split("-")[0],
-                                      wcs.cunit[yax])
-                wcs_axes.coords[0].set_axislabel(xlabel, fontproperties=fp)
-                wcs_axes.coords[1].set_axislabel(ylabel, fontproperties=fp)
-                wcs_axes.set_xlim(self.xlim[0].value, self.xlim[1].value)
-                wcs_axes.set_ylim(self.ylim[0].value, self.ylim[1].value)
-                wcs_axes.coords[0].ticklabels.set_fontproperties(fp)
-                wcs_axes.coords[1].ticklabels.set_fontproperties(fp)
+                if hasattr(self.pf.coordinates, "axis_default_unit_label"):
+                    axes_unit_labels = [self.pf.coordinates.axis_default_unit_name[xax],
+                                        self.pf.coordinates.axis_default_unit_name[yax]]
+                labels = [r'$\rm{'+axis_names[xax]+axes_unit_labels[0] + r'}$',
+                          r'$\rm{'+axis_names[yax]+axes_unit_labels[1] + r'}$']
+
+            self.plots[f].axes.set_xlabel(labels[0],fontproperties=fp)
+            self.plots[f].axes.set_ylabel(labels[1],fontproperties=fp)
+
+            for label in (self.plots[f].axes.get_xticklabels() +
+                          self.plots[f].axes.get_yticklabels() +
+                          [self.plots[f].axes.xaxis.get_offset_text(),
+                           self.plots[f].axes.yaxis.get_offset_text()]):
+                label.set_fontproperties(fp)
 
             colorbar_label = image.info['label']
 
@@ -1672,7 +1602,7 @@
 
 class WindowPlotMPL(ImagePlotMPL):
     def __init__(self, data, cbname, cmap, extent, zlim, figure_size, fontsize,
-                 unit_aspect, figure, axes, cax, wcs_axes=False):
+                 unit_aspect, figure, axes, cax):
         self._draw_colorbar = True
         self._draw_axes = True
         self._fontsize = fontsize
@@ -1689,10 +1619,6 @@
             fsize = figure_size
         self._cb_size = 0.0375*fsize
         self._ax_text_size = [0.9*fontscale, 0.7*fontscale]
-        if wcs_axes:
-            # Add a bit more space for the WCS coordinates
-            self._ax_text_size[0] *= 1.55
-            self._ax_text_size[1] *= 1.14
         self._top_buff_size = 0.30*fontscale
         self._aspect = ((extent[1] - extent[0])/(extent[3] - extent[2]))
 


https://bitbucket.org/yt_analysis/yt/commits/d4af70498fe8/
Changeset:   d4af70498fe8
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 19:25:11
Summary:     Some tidying up
Affected #:  1 file

diff -r c5e0902f5ba691a5f4f31597673e2d5a0a11206f -r d4af70498fe805ad92dca87e18c348e6d39774db yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -63,14 +63,12 @@
 class PlotWindowWCS(object):
     r"""
     Use the wcsaxes library to plot celestial coordinates on the axes.
+    See http://wcsaxes.readthedocs.org for details.
 
     Parameters
     ----------
-    set_axes : boolean
-        Turn on or off the WCS axes.
-    wcs_axes : WCSAxes instance
-        The WCSAxes instance, for adjusting the axes properties. See
-        http://wcsaxes.readthedocs.org for details.
+    pw : on-axis PlotWindow instance
+        The PlotWindow instance to add celestial axes to.
     """
     def __init__(self, pw):
         from wcsaxes import WCSAxes
@@ -80,12 +78,21 @@
             raise NotImplementedError("WCS axes are not implemented for this dataset.")
         if pw.data_source.axis != pw.pf.vel_axis:
             raise NotImplementedError("WCS axes are not implemented for this axis.")
+        self.pf = pw.pf
+        self.pw = pw
         self.plots = {}
+        self.wcs_axes = []
         for f in pw.plots:
             rect = pw.plots[f]._get_best_layout()[1]
             fig = pw.plots[f].figure
             ax = WCSAxes(fig, rect, wcs=pw.pf.wcs_2d, frameon=False)
             fig.add_axes(ax)
+            self.wcs_axes.append(ax)
+        self._setup_plots()
+
+    def _setup_plots(self):
+        pw = self.pw
+        for f, ax in zip(pw.plots, self.wcs_axes):
             wcs = ax.wcs.wcs
             pw.plots[f].axes.get_xaxis().set_visible(False)
             pw.plots[f].axes.get_yaxis().set_visible(False)
@@ -106,6 +113,9 @@
         self.pw = pw
         self.pf = self.pw.pf
 
+    def refresh(self):
+        self._setup_plots(self)
+
     def keys(self):
         return self.plots.keys()
 


https://bitbucket.org/yt_analysis/yt/commits/a10f0a7f607a/
Changeset:   a10f0a7f607a
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-02 20:33:14
Summary:     Cleaner way of generating the methods
Affected #:  1 file

diff -r d4af70498fe805ad92dca87e18c348e6d39774db -r a10f0a7f607a1d8a9b3c9e61cf766d89def7505e yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -60,6 +60,15 @@
         obj = ds.all_data()
     return obj.cut_region(["obj['%s'] > 0" % (reg_name)])
 
+plot_method_list = ["set_width","set_font","pan","set_font_size"
+                    "set_center","set_figure_size","set_window_size"]
+
+def plot_method_generator(pwwcs, method):
+    def _method(*args, **kwargs):
+        getattr(pwwcs.pw, method)(*args, **kwargs)
+        pwwcs._setup_plots()
+    setattr(pwwcs, method, _method)
+
 class PlotWindowWCS(object):
     r"""
     Use the wcsaxes library to plot celestial coordinates on the axes.
@@ -89,6 +98,8 @@
             fig.add_axes(ax)
             self.wcs_axes.append(ax)
         self._setup_plots()
+        for plot_method in plot_method_list:
+            plot_method_generator(self, plot_method)
 
     def _setup_plots(self):
         pw = self.pw


https://bitbucket.org/yt_analysis/yt/commits/36206326e054/
Changeset:   36206326e054
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-03 06:04:52
Summary:     Docstring fix
Affected #:  1 file

diff -r a10f0a7f607a1d8a9b3c9e61cf766d89def7505e -r 36206326e05485c091b2b937d494739acf651f6b yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -71,8 +71,8 @@
 
 class PlotWindowWCS(object):
     r"""
-    Use the wcsaxes library to plot celestial coordinates on the axes.
-    See http://wcsaxes.readthedocs.org for details.
+    Use the wcsaxes library to plot celestial coordinates on the axes of a
+    on-axis PlotWindow plot. See http://wcsaxes.readthedocs.org for details.
 
     Parameters
     ----------


https://bitbucket.org/yt_analysis/yt/commits/a54eb68188f2/
Changeset:   a54eb68188f2
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 22:52:46
Summary:     Merge
Affected #:  8 files

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r a54eb68188f24a47fa8c7f75abad53163f3cab3f yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -54,6 +54,8 @@
     SphericalCoordinateHandler
 from yt.geometry.geographic_coordinates import \
     GeographicCoordinateHandler
+from yt.geometry.ppv_coordinates import \
+    PPVCoordinateHandler
 
 # We want to support the movie format in the future.
 # When such a thing comes to pass, I'll move all the stuff that is contant up
@@ -370,6 +372,8 @@
             self.coordinates = SphericalCoordinateHandler(self)
         elif self.geometry == "geographic":
             self.coordinates = GeographicCoordinateHandler(self)
+        elif self.geometry == "ppv":
+            self.coordinates = PPVCoordinateHandler(self)
         else:
             raise YTGeometryNotSupported(self.geometry)
 

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r a54eb68188f24a47fa8c7f75abad53163f3cab3f yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -494,6 +494,8 @@
     def _setup_ppv(self):
 
         self.ppv_data = True
+        self.geometry = "ppv"
+
         end = min(self.dimensionality+1,4)
         if self.events_data:
             ctypes = self.axis_names

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r a54eb68188f24a47fa8c7f75abad53163f3cab3f yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -11,10 +11,11 @@
 #-----------------------------------------------------------------------------
 
 import numpy as np
-from yt.fields.api import add_field
 from yt.fields.derived_field import ValidateSpatial
-from yt.funcs import mylog
 from yt.utilities.on_demand_imports import _astropy
+from yt.funcs import mylog, get_image_suffix
+from yt.visualization._mpl_imports import FigureCanvasAgg
+import os
 
 def _make_counts(emin, emax):
     def _counts(field, data):
@@ -60,4 +61,117 @@
         ds.add_field((ftype,fname), function=cfunc,
                      units="counts/pixel",
                      validators = [ValidateSpatial()],
-                     display_name="Counts (%s-%s keV)" % (emin, emax))
\ No newline at end of file
+                     display_name="Counts (%s-%s keV)" % (emin, emax))
+
+def ds9_region(ds, reg, obj=None):
+    import pyregion
+    r = pyregion.open(reg)
+    reg_name = reg.split(".")[0]
+    nx = ds.domain_dimensions[ds.lon_axis]
+    ny = ds.domain_dimensions[ds.lat_axis]
+    mask = r.get_mask(header=ds.wcs_2d.to_header(),
+                      shape=[nx,ny])
+    def _reg_field(field, data):
+        i = data["x"].ndarray_view().astype("int")-1
+        j = data["y"].ndarray_view().astype("int")-1
+        new_mask = mask[i,j]
+        ret = data["zeros"].copy()
+        ret[new_mask] = 1.
+        return ret
+    ds.add_field(("gas",reg_name), function=_reg_field)
+    if obj is None:
+        obj = ds.all_data()
+    return obj.cut_region(["obj['%s'] > 0" % (reg_name)])
+
+plot_method_list = ["set_width","set_font","pan","set_font_size"
+                    "set_center","set_figure_size","set_window_size"]
+
+def plot_method_generator(pwwcs, method):
+    def _method(*args, **kwargs):
+        getattr(pwwcs.pw, method)(*args, **kwargs)
+        pwwcs._setup_plots()
+    setattr(pwwcs, method, _method)
+
+class PlotWindowWCS(object):
+    r"""
+    Use the wcsaxes library to plot celestial coordinates on the axes of a
+    on-axis PlotWindow plot. See http://wcsaxes.readthedocs.org for details.
+
+    Parameters
+    ----------
+    pw : on-axis PlotWindow instance
+        The PlotWindow instance to add celestial axes to.
+    """
+    def __init__(self, pw):
+        from wcsaxes import WCSAxes
+        if pw.oblique:
+            raise NotImplementedError("WCS axes are not implemented for oblique plots.")
+        if not hasattr(pw.pf, "wcs_2d"):
+            raise NotImplementedError("WCS axes are not implemented for this dataset.")
+        if pw.data_source.axis != pw.pf.vel_axis:
+            raise NotImplementedError("WCS axes are not implemented for this axis.")
+        self.pf = pw.pf
+        self.pw = pw
+        self.plots = {}
+        self.wcs_axes = []
+        for f in pw.plots:
+            rect = pw.plots[f]._get_best_layout()[1]
+            fig = pw.plots[f].figure
+            ax = WCSAxes(fig, rect, wcs=pw.pf.wcs_2d, frameon=False)
+            fig.add_axes(ax)
+            self.wcs_axes.append(ax)
+        self._setup_plots()
+        for plot_method in plot_method_list:
+            plot_method_generator(self, plot_method)
+
+    def _setup_plots(self):
+        pw = self.pw
+        for f, ax in zip(pw.plots, self.wcs_axes):
+            wcs = ax.wcs.wcs
+            pw.plots[f].axes.get_xaxis().set_visible(False)
+            pw.plots[f].axes.get_yaxis().set_visible(False)
+            xax = pw.pf.coordinates.x_axis[pw.data_source.axis]
+            yax = pw.pf.coordinates.y_axis[pw.data_source.axis]
+            xlabel = "%s (%s)" % (wcs.ctype[xax].split("-")[0],
+                                  wcs.cunit[xax])
+            ylabel = "%s (%s)" % (wcs.ctype[yax].split("-")[0],
+                                  wcs.cunit[yax])
+            fp = pw._font_properties
+            ax.coords[0].set_axislabel(xlabel, fontproperties=fp)
+            ax.coords[1].set_axislabel(ylabel, fontproperties=fp)
+            ax.set_xlim(pw.xlim[0].value, pw.xlim[1].value)
+            ax.set_ylim(pw.ylim[0].value, pw.ylim[1].value)
+            ax.coords[0].ticklabels.set_fontproperties(fp)
+            ax.coords[1].ticklabels.set_fontproperties(fp)
+            self.plots[f] = pw.plots[f]
+        self.pw = pw
+        self.pf = self.pw.pf
+
+    def refresh(self):
+        self._setup_plots(self)
+
+    def keys(self):
+        return self.plots.keys()
+
+    def values(self):
+        return self.plots.values()
+
+    def items(self):
+        return self.plots.items()
+
+    def __getitem__(self, key):
+        for k in self.keys():
+            if k[1] == key:
+                return self.plots[k]
+
+    def show(self):
+        from IPython.core.display import display
+        for k, v in sorted(self.plots.iteritems()):
+            canvas = FigureCanvasAgg(v.figure)
+            display(v.figure)
+
+    def save(self, name=None, mpl_kwargs=None):
+        if mpl_kwargs is None:
+            mpl_kwargs = {}
+        mpl_kwargs["bbox_inches"] = "tight"
+        self.pw.save(name=name, mpl_kwargs=mpl_kwargs)

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r a54eb68188f24a47fa8c7f75abad53163f3cab3f yt/geometry/ppv_coordinates.py
--- /dev/null
+++ b/yt/geometry/ppv_coordinates.py
@@ -0,0 +1,72 @@
+"""
+Cartesian fields
+
+
+
+
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+import numpy as np
+from .cartesian_coordinates import \
+    CartesianCoordinateHandler
+
+class PPVCoordinateHandler(CartesianCoordinateHandler):
+
+    def __init__(self, pf):
+        super(PPVCoordinateHandler, self).__init__(pf)
+
+        self.axis_name = {}
+        self.axis_id = {}
+        self.x_axis = {}
+        self.y_axis = {}
+
+        for axis, axis_name in zip([pf.lon_axis, pf.lat_axis, pf.vel_axis],
+                                   ["Image\ x", "Image\ y", pf.vel_name]):
+            lower_ax = "xyz"[axis]
+            upper_ax = lower_ax.upper()
+
+            self.axis_name[axis] = axis_name
+            self.axis_name[lower_ax] = axis_name
+            self.axis_name[upper_ax] = axis_name
+            self.axis_name[axis_name] = axis_name
+
+            self.axis_id[lower_ax] = axis
+            self.axis_id[axis] = axis
+            self.axis_id[axis_name] = axis
+
+            if axis == 0:
+                self.x_axis[axis] = 1
+                self.x_axis[lower_ax] = 1
+                self.x_axis[axis_name] = 1
+            else:
+                self.x_axis[axis] = 0
+                self.x_axis[lower_ax] = 0
+                self.x_axis[axis_name] = 0
+
+            if axis == 2:
+                self.y_axis[axis] = 1
+                self.y_axis[lower_ax] = 1
+                self.y_axis[axis_name] = 1
+            else:
+                self.y_axis[axis] = 2
+                self.y_axis[lower_ax] = 2
+                self.y_axis[axis_name] = 2
+
+        self.default_unit_label = {}
+        self.default_unit_label[pf.lon_axis] = "pixel"
+        self.default_unit_label[pf.lat_axis] = "pixel"
+        self.default_unit_label[pf.vel_axis] = pf.vel_unit
+
+    def convert_to_cylindrical(self, coord):
+        raise NotImplementedError
+
+    def convert_from_cylindrical(self, coord):
+        raise NotImplementedError

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r a54eb68188f24a47fa8c7f75abad53163f3cab3f yt/units/unit_object.py
--- a/yt/units/unit_object.py
+++ b/yt/units/unit_object.py
@@ -358,7 +358,8 @@
         for ex in self.expr.free_symbols:
             symbol_table[ex] = latex_symbol_lut[str(ex)]
         return latex(self.expr, symbol_names=symbol_table,
-                     fold_frac_powers=True, fold_short_frac=True)
+                     mul_symbol="dot", fold_frac_powers=True,
+                     fold_short_frac=True)
 #
 # Unit manipulation functions
 #

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r a54eb68188f24a47fa8c7f75abad53163f3cab3f yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -17,7 +17,7 @@
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \
-    get_image_suffix, mylog
+    get_image_suffix, mylog, iterable
 import numpy as np
 
 class CallbackWrapper(object):
@@ -140,12 +140,16 @@
             top_buff_size = 0.0
 
         # Ensure the figure size along the long axis is always equal to _figure_size
-        if self._aspect >= 1.0:
-            x_fig_size = self._figure_size
-            y_fig_size = self._figure_size/self._aspect
-        if self._aspect < 1.0:
-            x_fig_size = self._figure_size*self._aspect
-            y_fig_size = self._figure_size
+        if iterable(self._figure_size):
+            x_fig_size = self._figure_size[0]
+            y_fig_size = self._figure_size[1]
+        else:
+            if self._aspect >= 1.0:
+                x_fig_size = self._figure_size
+                y_fig_size = self._figure_size/self._aspect
+            if self._aspect < 1.0:
+                x_fig_size = self._figure_size*self._aspect
+                y_fig_size = self._figure_size
 
         xbins = np.array([x_axis_size, x_fig_size, cb_size, cb_text_size])
         ybins = np.array([y_axis_size, y_fig_size, top_buff_size])

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r a54eb68188f24a47fa8c7f75abad53163f3cab3f yt/visualization/plot_container.py
--- a/yt/visualization/plot_container.py
+++ b/yt/visualization/plot_container.py
@@ -16,7 +16,7 @@
 
 from yt.funcs import \
     defaultdict, get_image_suffix, \
-    get_ipython_api_version
+    get_ipython_api_version, iterable
 from yt.utilities.exceptions import \
     YTNotInsideNotebook
 from ._mpl_imports import FigureCanvasAgg
@@ -111,7 +111,10 @@
 
     def __init__(self, data_source, figure_size, fontsize):
         self.data_source = data_source
-        self.figure_size = float(figure_size)
+        if iterable(figure_size):
+            self.figure_size = float(figure_size[0]), float(figure_size[1])
+        else:
+            self.figure_size = float(figure_size)
         self.plots = PlotDictionary(data_source)
         self._callbacks = []
         self._field_transform = {}

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r a54eb68188f24a47fa8c7f75abad53163f3cab3f yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -161,7 +161,7 @@
     return center
 
 def get_window_parameters(axis, center, width, pf):
-    if pf.geometry == "cartesian":
+    if pf.geometry == "cartesian" or pf.geometry == "ppv":
         width = get_sanitized_width(axis, width, None, pf)
         center = get_sanitized_center(center, pf)
     elif pf.geometry in ("polar", "cylindrical"):
@@ -269,7 +269,7 @@
     _frb = None
     def __init__(self, data_source, bounds, buff_size=(800,800), antialias=True,
                  periodic=True, origin='center-window', oblique=False,
-                 window_size=8.0, fields=None, fontsize=18, setup=False):
+                 window_size=8.0, fields=None, fontsize=18, aspect=None, setup=False):
         if not hasattr(self, "pf"):
             self.pf = data_source.pf
             ts = self._initialize_dataset(self.pf)
@@ -281,6 +281,7 @@
         self.oblique = oblique
         self.buff_size = buff_size
         self.antialias = antialias
+        self.aspect = aspect
         skip = list(FixedResolutionBuffer._exclude_fields) + data_source._key_fields
         if fields is None:
             fields = []
@@ -624,7 +625,7 @@
         Examples
         --------
 
-        >>> p = ProjectionPlot(pf, "y", "Density")
+        >>> p = ProjectionPlot(pf, "y", "density")
         >>> p.show()
         >>> p.set_axes_unit("kpc")
         >>> p.show()
@@ -734,7 +735,8 @@
             else:
                 (unit_x, unit_y) = self._axes_unit_names
 
-            aspect = np.float64(self.pf.quan(1.0, unit_y)/self.pf.quan(1.0, unit_x))
+            if self.aspect is None:
+                self.aspect = np.float64(self.pf.quan(1.0, unit_y)/(self.pf.quan(1.0, unit_x)))
 
             extentx = [(self.xlim[i] - xc).in_units(unit_x) for i in (0, 1)]
             extenty = [(self.ylim[i] - yc).in_units(unit_y) for i in (0, 1)]
@@ -775,12 +777,17 @@
                 image, self._field_transform[f].name,
                 self._colormaps[f], extent, zlim,
                 self.figure_size, fp.get_size(),
-                aspect, fig, axes, cax)
+                self.aspect, fig, axes, cax)
 
             axes_unit_labels = ['', '']
             comoving = False
             hinv = False
             for i, un in enumerate((unit_x, unit_y)):
+                if hasattr(self.pf.coordinates, "default_unit_label"):
+                    axax = getattr(self.pf.coordinates, "%s_axis" % ("xy"[i]))[axis_index]
+                    un = self.pf.coordinates.default_unit_label[axax]
+                    axes_unit_labels[i] = '\/\/('+un+')'
+                    continue
                 # Use sympy to factor h out of the unit.  In this context 'un'
                 # is a string, so we call the Unit constructor.
                 expr = Unit(un, registry=self.pf.unit_registry).expr
@@ -815,6 +822,9 @@
                 axis_names = self.pf.coordinates.axis_name
                 xax = self.pf.coordinates.x_axis[axis_index]
                 yax = self.pf.coordinates.y_axis[axis_index]
+                if hasattr(self.pf.coordinates, "axis_default_unit_label"):
+                    axes_unit_labels = [self.pf.coordinates.axis_default_unit_name[xax],
+                                        self.pf.coordinates.axis_default_unit_name[yax]]
                 labels = [r'$\rm{'+axis_names[xax]+axes_unit_labels[0] + r'}$',
                           r'$\rm{'+axis_names[yax]+axes_unit_labels[1] + r'}$']
 
@@ -992,7 +1002,7 @@
     _frb_generator = FixedResolutionBuffer
 
     def __init__(self, pf, axis, fields, center='c', width=None, axes_unit=None,
-                 origin='center-window', fontsize=18, field_parameters=None):
+                 origin='center-window', fontsize=18, field_parameters=None, **kwargs):
         # this will handle time series data and controllers
         ts = self._initialize_dataset(pf)
         self.ts = ts
@@ -1004,7 +1014,7 @@
             field_parameters = field_parameters, center=center)
         slc.get_data(fields)
         PWViewerMPL.__init__(self, slc, bounds, origin=origin,
-                             fontsize=fontsize, fields=fields)
+                             fontsize=fontsize, fields=fields, **kwargs)
         if axes_unit is None:
             axes_unit = get_axes_unit(width, pf)
         self.set_axes_unit(axes_unit)
@@ -1119,7 +1129,7 @@
     def __init__(self, pf, axis, fields, center='c', width=None, axes_unit=None,
                  weight_field=None, max_level=None, origin='center-window',
                  fontsize=18, field_parameters=None, data_source=None,
-                 proj_style = "integrate"):
+                 proj_style = "integrate", **kwargs):
         ts = self._initialize_dataset(pf)
         self.ts = ts
         pf = self.pf = ts[0]
@@ -1130,7 +1140,7 @@
                          center=center, data_source=data_source,
                          field_parameters = field_parameters, style = proj_style)
         PWViewerMPL.__init__(self, proj, bounds, fields=fields, origin=origin,
-                             fontsize=fontsize)
+                             fontsize=fontsize, **kwargs)
         if axes_unit is None:
             axes_unit = get_axes_unit(width, pf)
         self.set_axes_unit(axes_unit)
@@ -1603,7 +1613,11 @@
         if fontscale < 1.0:
             fontscale = np.sqrt(fontscale)
 
-        self._cb_size = 0.0375*figure_size
+        if iterable(figure_size):
+            fsize = figure_size[0]
+        else:
+            fsize = figure_size
+        self._cb_size = 0.0375*fsize
         self._ax_text_size = [0.9*fontscale, 0.7*fontscale]
         self._top_buff_size = 0.30*fontscale
         self._aspect = ((extent[1] - extent[0])/(extent[3] - extent[2]))


https://bitbucket.org/yt_analysis/yt/commits/c1ac04055822/
Changeset:   c1ac04055822
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 22:59:32
Summary:     Docstrings
Affected #:  1 file

diff -r a54eb68188f24a47fa8c7f75abad53163f3cab3f -r c1ac040558221b2fda1453cd7a4fab72e26bc551 yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -47,6 +47,8 @@
     ebounds : list of tuples
         A list of tuples, one for each field, with (emin, emax) as the
         energy bounds for the image.
+    ftype : string, optional
+        The field type of the resulting field. Defaults to "gas".
 
     Examples
     --------
@@ -64,6 +66,26 @@
                      display_name="Counts (%s-%s keV)" % (emin, emax))
 
 def ds9_region(ds, reg, obj=None):
+    r"""
+    Create a data container from a ds9 region file. Requires the pyregion
+    package (http://leejjoon.github.io/pyregion/) to be installed.
+
+    Parameters
+    ----------
+    ds : FITSDataset
+        The Dataset to create the region from.
+    reg : string
+        The filename of the ds9 region.
+    obj : data container, optional
+        The data container that will be used to create the new region.
+        Defaults to ds.all_data.
+
+    Examples
+    --------
+
+    ds = yt.load("m33_hi.fits")
+
+    """
     import pyregion
     r = pyregion.open(reg)
     reg_name = reg.split(".")[0]
@@ -78,7 +100,7 @@
         ret = data["zeros"].copy()
         ret[new_mask] = 1.
         return ret
-    ds.add_field(("gas",reg_name), function=_reg_field)
+    ds.add_field(("index",reg_name), function=_reg_field)
     if obj is None:
         obj = ds.all_data()
     return obj.cut_region(["obj['%s'] > 0" % (reg_name)])


https://bitbucket.org/yt_analysis/yt/commits/6d8f7a82b5ea/
Changeset:   6d8f7a82b5ea
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 04:56:46
Summary:     Merge
Affected #:  3 files

diff -r c1ac040558221b2fda1453cd7a4fab72e26bc551 -r 6d8f7a82b5ea7ab667497e0853b239fafe9df408 doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
--- a/doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
+++ b/doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:29046b1f2a13c62992ee4b7413fac78782a397df6b0b66488d4d880fa18426a9"
+  "signature": "sha256:b7541e0167001c6dd74306c8490385ace7bdb0533a829286f0505c0b24c67f16"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -325,7 +325,8 @@
      "input": [
       "from astropy import units as u\n",
       "x = 42.0 * u.meter\n",
-      "y = YTQuantity(x)"
+      "y = YTQuantity(x)\n",
+      "y2 = YTQuantity.from_astropy(x) # Another way to create the quantity"
      ],
      "language": "python",
      "metadata": {},
@@ -336,7 +337,8 @@
      "collapsed": false,
      "input": [
       "print x, type(x)\n",
-      "print y, type(y)"
+      "print y, type(y)\n",
+      "print y2, type(y2)"
      ],
      "language": "python",
      "metadata": {},
@@ -347,7 +349,8 @@
      "collapsed": false,
      "input": [
       "a = np.random.random(size=10) * u.km/u.s\n",
-      "b = YTArray(a)"
+      "b = YTArray(a)\n",
+      "b2 = YTArray.from_astropy(a) # Another way to create the quantity"
      ],
      "language": "python",
      "metadata": {},
@@ -358,7 +361,8 @@
      "collapsed": false,
      "input": [
       "print a, type(a)\n",
-      "print b, type(b)"
+      "print b, type(b)\n",
+      "print b2, type(b2)"
      ],
      "language": "python",
      "metadata": {},

diff -r c1ac040558221b2fda1453cd7a4fab72e26bc551 -r 6d8f7a82b5ea7ab667497e0853b239fafe9df408 yt/units/tests/test_ytarray.py
--- a/yt/units/tests/test_ytarray.py
+++ b/yt/units/tests/test_ytarray.py
@@ -634,15 +634,19 @@
 
     ap_arr = np.arange(10)*_astropy.units.km/_astropy.units.hr
     yt_arr = YTArray(np.arange(10), "km/hr")
+    yt_arr2 = YTArray.from_astropy(ap_arr)
 
     ap_quan = 10.*_astropy.units.Msun**0.5/(_astropy.units.kpc**3)
     yt_quan = YTQuantity(10.,"sqrt(Msun)/kpc**3")
+    yt_quan2 = YTQuantity.from_astropy(ap_quan)
 
     yield assert_array_equal, ap_arr, yt_arr.to_astropy()
     yield assert_array_equal, yt_arr, YTArray(ap_arr)
+    yield assert_array_equal, yt_arr, yt_arr2
 
     yield assert_equal, ap_quan, yt_quan.to_astropy()
     yield assert_equal, yt_quan, YTQuantity(ap_quan)
+    yield assert_equal, yt_quan, yt_quan2
 
     yield assert_array_equal, yt_arr, YTArray(yt_arr.to_astropy())
     yield assert_equal, yt_quan, YTQuantity(yt_quan.to_astropy())

diff -r c1ac040558221b2fda1453cd7a4fab72e26bc551 -r 6d8f7a82b5ea7ab667497e0853b239fafe9df408 yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -253,20 +253,7 @@
                     )
         if _astropy.units is not None:
             if isinstance(input_array, _astropy.units.quantity.Quantity):
-                # Converting from AstroPy Quantity
-                u = input_array.unit
-                ap_units = []
-                for base, power in zip(u.bases, u.powers):
-                    unit_str = base.to_string()
-                    # we have to do this because AstroPy is silly and defines
-                    # hour as "h"
-                    if unit_str == "h": unit_str = "hr"
-                    ap_units.append("%s**(%s)" % (unit_str, Rational(power)))
-                ap_units = "*".join(ap_units)
-                if isinstance(input_array.value, np.ndarray):
-                    return YTArray(input_array.value, ap_units)
-                else:
-                    return YTQuantity(input_array.value, ap_units)
+                return cls.from_astropy(input_array)
         if isinstance(input_array, YTArray):
             if input_units is None:
                 if registry is None:
@@ -442,6 +429,28 @@
         """
         return np.array(self)
 
+    @classmethod
+    def from_astropy(cls, arr):
+        """
+        Creates a new YTArray with the same unit information from an
+        AstroPy quantity *arr*.
+        """
+        # Converting from AstroPy Quantity
+        u = arr.unit
+        ap_units = []
+        for base, power in zip(u.bases, u.powers):
+            unit_str = base.to_string()
+            # we have to do this because AstroPy is silly and defines
+            # hour as "h"
+            if unit_str == "h": unit_str = "hr"
+            ap_units.append("%s**(%s)" % (unit_str, Rational(power)))
+        ap_units = "*".join(ap_units)
+        if isinstance(arr.value, np.ndarray):
+            return YTArray(arr.value, ap_units)
+        else:
+            return YTQuantity(arr.value, ap_units)
+
+
     def to_astropy(self, **kwargs):
         """
         Creates a new AstroPy quantity with the same unit information.


https://bitbucket.org/yt_analysis/yt/commits/bf3a99952c4e/
Changeset:   bf3a99952c4e
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 06:32:47
Summary:     Projections where the values are simply summed along the axis instead of integrated with a path length. Might only make sense for uniformly gridded data.
Affected #:  1 file

diff -r 6d8f7a82b5ea7ab667497e0853b239fafe9df408 -r bf3a99952c4ebd06f1ed085a840779f9beb5ad11 yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -156,7 +156,7 @@
     simulation domain.
 
     This object is typically accessed through the `proj` object that
-    hangs off of index objects.  AMRQuadProj is a projection of a
+    hangs off of index objects.  YTQuadTreeProj is a projection of a
     `field` along an `axis`.  The field can have an associated
     `weight_field`, in which case the values are multiplied by a weight
     before being summed, and then divided by the sum of that weight; the
@@ -189,29 +189,21 @@
     data_source : `yt.data_objects.api.AMRData`, optional
         If specified, this will be the data source used for selecting
         regions to project.
-    node_name: string, optional
-        The node in the .yt file to find or store this slice at.  Should
-        probably not be used.
-    field_cuts : list of strings, optional
-        If supplied, each of these strings will be evaluated to cut a
-        region of a grid out.  They can be of the form "grid['Temperature']
-        > 100" for instance.
-    preload_style : string
-        Either 'level', 'all', or None (default).  Defines how grids are
-        loaded -- either level by level, or all at once.  Only applicable
-        during parallel runs.
-    serialize : bool, optional
-        Whether we should store this projection in the .yt file or not.
-    kwargs : dict of items
-        Any additional values are passed as field parameters that can be
+    style : string, optional
+        The style of projection to be performed.
+        "integrate" : integration along the axis
+        "mip" : maximum intensity projection
+        "sum" : same as "integrate", except that we don't multiply by the path length
+    field_parameters : dict of items
+        Values to be passed as field parameters that can be
         accessed by generated fields.
 
     Examples
     --------
 
-    >>> pf = load("RedshiftOutput0005")
-    >>> qproj = pf.h.quad_proj(0, "Density")
-    >>> print qproj["Density"]
+    >>> ds = load("RedshiftOutput0005")
+    >>> prj = ds.proj(0, "density")
+    >>> print proj["density"]
     """
     _key_fields = YTSelectionContainer2D._key_fields + ['weight_field']
     _type_name = "proj"
@@ -221,10 +213,15 @@
                  center = None, pf = None, data_source=None, 
                  style = "integrate", field_parameters = None):
         YTSelectionContainer2D.__init__(self, axis, pf, field_parameters)
-        self.proj_style = style
+        if style == "sum":
+            self.proj_style = "integrate"
+            self.sum_only = True
+        else:
+            self.proj_style = style
+            self.sum_only = False
         if style == "mip":
             self.func = np.max
-        elif style == "integrate":
+        elif style == "integrate" or style == "sum":
             self.func = np.sum # for the future
         else:
             raise NotImplementedError(style)
@@ -358,7 +355,7 @@
         tree.initialize_chunk(i1, i2, ilevel)
 
     def _handle_chunk(self, chunk, fields, tree):
-        if self.proj_style == "mip":
+        if self.proj_style == "mip" or self.sum_only:
             dl = 1.0
         else:
             # This gets explicitly converted to cm


https://bitbucket.org/yt_analysis/yt/commits/7198bfbfc0ea/
Changeset:   7198bfbfc0ea
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 06:54:04
Summary:     Fixing some bugs
Affected #:  2 files

diff -r bf3a99952c4ebd06f1ed085a840779f9beb5ad11 -r 7198bfbfc0ea21fef5b06bb88d3ad8dc9749df36 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -95,7 +95,7 @@
             # the right case by comparing against known units. This
             # only really works for common units.
             units = set(re.split(regex_pattern, field_units))
-            units.remove('')
+            if '' in units: units.remove('')
             n = int(0)
             for unit in units:
                 if unit in known_units:

diff -r bf3a99952c4ebd06f1ed085a840779f9beb5ad11 -r 7198bfbfc0ea21fef5b06bb88d3ad8dc9749df36 yt/frontends/fits/io.py
--- a/yt/frontends/fits/io.py
+++ b/yt/frontends/fits/io.py
@@ -54,7 +54,7 @@
         z = np.ones(x.shape)
         x = (x-0.5)/self.pf.reblock+0.5
         y = (y-0.5)/self.pf.reblock+0.5
-        mask = selector.select_points(x, y, z)
+        mask = selector.select_points(x, y, z, 0.0)
         if mask is None: return
         for field in field_list:
             fd = field.split("_")[-1]


https://bitbucket.org/yt_analysis/yt/commits/de8d62b87077/
Changeset:   de8d62b87077
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 07:15:00
Summary:     The results of applying these are unexpected, so best to remove them and just get the plot in the right shape before applying the wcsaxes.
Affected #:  1 file

diff -r 7198bfbfc0ea21fef5b06bb88d3ad8dc9749df36 -r de8d62b870777338dbd85b0874c4424e14b5dc6f yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -105,15 +105,6 @@
         obj = ds.all_data()
     return obj.cut_region(["obj['%s'] > 0" % (reg_name)])
 
-plot_method_list = ["set_width","set_font","pan","set_font_size"
-                    "set_center","set_figure_size","set_window_size"]
-
-def plot_method_generator(pwwcs, method):
-    def _method(*args, **kwargs):
-        getattr(pwwcs.pw, method)(*args, **kwargs)
-        pwwcs._setup_plots()
-    setattr(pwwcs, method, _method)
-
 class PlotWindowWCS(object):
     r"""
     Use the wcsaxes library to plot celestial coordinates on the axes of a
@@ -143,8 +134,6 @@
             fig.add_axes(ax)
             self.wcs_axes.append(ax)
         self._setup_plots()
-        for plot_method in plot_method_list:
-            plot_method_generator(self, plot_method)
 
     def _setup_plots(self):
         pw = self.pw


https://bitbucket.org/yt_analysis/yt/commits/c4605258cec7/
Changeset:   c4605258cec7
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 07:35:36
Summary:     Docstring
Affected #:  1 file

diff -r de8d62b870777338dbd85b0874c4424e14b5dc6f -r c4605258cec7935d7a3371e4f8c76fff9becddae yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -83,8 +83,9 @@
     Examples
     --------
 
-    ds = yt.load("m33_hi.fits")
-
+    >>> ds = yt.load("m33_hi.fits")
+    >>> circle_region = ds9_region(ds, "circle.reg")
+    >>> print circle_region.quantities.extrema("flux")
     """
     import pyregion
     r = pyregion.open(reg)


https://bitbucket.org/yt_analysis/yt/commits/9ad126c45f1b/
Changeset:   9ad126c45f1b
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 16:22:30
Summary:     Everything is in place here now for FITS docs
Affected #:  1 file

diff -r c4605258cec7935d7a3371e4f8c76fff9becddae -r 9ad126c45f1b6ebada495109755666ebee9e872e doc/source/examining/loading_data.rst
--- a/doc/source/examining/loading_data.rst
+++ b/doc/source/examining/loading_data.rst
@@ -557,11 +557,11 @@
 
 .. parsed-literal::
 
-  level	  # grids	    # cells	   # cells^3
-  ----------------------------------------------
-    0	     512	  981940800	         994
-  ----------------------------------------------
-             512	  981940800
+  level	  # grids     # cells     # cells^3
+  ------------------------------------------
+    0	     512     981940800	     994
+  ------------------------------------------
+             512     981940800
 
 yt will generate its own domain decomposition, but the number of grids can be
 set manually by passing the ``nprocs`` parameter to the ``load`` call:
@@ -676,7 +676,7 @@
 single floating-point number (applies to all fields) or a Python dictionary
 containing different mask values for different fields:
 
-.. code-block::
+.. code-block:: python
 
   # passing a single float
   ds = load("m33_hi.fits", nan_mask=0.0)
@@ -688,10 +688,68 @@
 files, many of which you may want to ignore. If you want to see these
 warnings, set ``suppress_astropy_warnings = False`` in the call to ``load``.
 
+Miscellaneous Tools for Use with FITS Data
+++++++++++++++++++++++++++++++++++++++++++
+
+A number of tools have been prepared for use with FITS data that enhance yt's visualization and
+analysis capabilities for this particular type of data. These are included in the ``yt.frontends.fits.misc`` module, and can be imported like so:
+
+.. code-block:: python
+
+  from yt.frontends.fits.misc import setup_counts_fields, PlotWindowWCS, ds9_region
+
+
+``setup_counts_fields``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+This function can be used to create image fields from X-ray counts data in different energy bands:
+
+.. code-block:: python
+
+  ebounds = [(0.1,2.0),(2.0,5.0)] # Energies are in keV
+  setup_counts_fields(ds, ebounds)
+
+which would make two fields, ``"counts_0.1-2.0"`` and ``"counts_2.0-5.0"``,
+and add them to the field registry for the dataset ``ds``.
+
+
+``ds9_region``
+~~~~~~~~~~~~~~
+
+This function takes a `ds9 <http://ds9.si.edu/site/Home.html>`_ region and creates a "cut region"
+data container from it, that can be used to select the cells in the FITS dataset that fall within
+the region. To use this functionality, the `pyregion <http://leejjoon.github.io/pyregion/>`_
+package must be installed.
+
+.. code-block:: python
+
+  ds = yt.load("m33_hi.fits")
+  circle_region = ds9_region(ds, "circle.reg")
+  print circle_region.quantities.extrema("flux")
+
+
+``PlotWindowWCS``
+~~~~~~~~~~~~~~~~~
+
+This class takes a on-axis ``SlicePlot`` or ``ProjectionPlot`` of FITS data and adds celestial
+coordinates to the plot axes. To use it, the `WCSAxes <http://wcsaxes.readthedocs.org>`_
+package must be installed.
+
+.. code-block:: python
+
+  wcs_slc = PlotWindowWCS(slc)
+  wcs_slc.show() # for the IPython notebook
+  wcs_slc.save()
+
+``WCSAxes`` is still in an experimental state, but as its functionality improves it will be
+utilized more here.
+
+
 Examples of Using FITS Data
 +++++++++++++++++++++++++++
 
-The following IPython notebooks show examples of working with FITS data in yt:
+The following IPython notebooks show examples of working with FITS data in yt,
+which we recommend you look at in the following order:
 
 * :ref:`radio_cubes`
 * :ref:`xray_fits`


https://bitbucket.org/yt_analysis/yt/commits/41e6f4f08ee3/
Changeset:   41e6f4f08ee3
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 18:39:05
Summary:     Improvements--bug fixes, parse region strings, and add field parameters
Affected #:  1 file

diff -r 9ad126c45f1b6ebada495109755666ebee9e872e -r 41e6f4f08ee37a1b4bb8b6fd7c1e8752c7750e66 yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -65,7 +65,7 @@
                      validators = [ValidateSpatial()],
                      display_name="Counts (%s-%s keV)" % (emin, emax))
 
-def ds9_region(ds, reg, obj=None):
+def ds9_region(ds, reg, obj=None, field_parameters=None):
     r"""
     Create a data container from a ds9 region file. Requires the pyregion
     package (http://leejjoon.github.io/pyregion/) to be installed.
@@ -75,10 +75,12 @@
     ds : FITSDataset
         The Dataset to create the region from.
     reg : string
-        The filename of the ds9 region.
+        The filename of the ds9 region, or a region string to be parsed.
     obj : data container, optional
         The data container that will be used to create the new region.
         Defaults to ds.all_data.
+    field_parameters : dictionary, optional
+        A set of field parameters to apply to the region.
 
     Examples
     --------
@@ -88,22 +90,28 @@
     >>> print circle_region.quantities.extrema("flux")
     """
     import pyregion
-    r = pyregion.open(reg)
+    if os.path.exists(reg):
+        r = pyregion.open(reg)
+    else:
+        r = pyregion.parse(reg)
+    filter = r.get_filter(header=ds.wcs_2d.to_header())
     reg_name = reg.split(".")[0]
     nx = ds.domain_dimensions[ds.lon_axis]
     ny = ds.domain_dimensions[ds.lat_axis]
-    mask = r.get_mask(header=ds.wcs_2d.to_header(),
-                      shape=[nx,ny])
+    mask = filter.mask((ny,nx)).transpose()
     def _reg_field(field, data):
-        i = data["x"].ndarray_view().astype("int")-1
-        j = data["y"].ndarray_view().astype("int")-1
+        i = data["xyz"[ds.lon_axis]].ndarray_view().astype("int")-1
+        j = data["xyz"[ds.lat_axis]].ndarray_view().astype("int")-1
         new_mask = mask[i,j]
         ret = data["zeros"].copy()
         ret[new_mask] = 1.
         return ret
-    ds.add_field(("index",reg_name), function=_reg_field)
+    ds.add_field(("gas",reg_name), function=_reg_field)
     if obj is None:
         obj = ds.all_data()
+    if field_parameters is not None:
+        for k,v in field_parameters.items():
+            obj.set_field_parameter(k,v)
     return obj.cut_region(["obj['%s'] > 0" % (reg_name)])
 
 class PlotWindowWCS(object):


https://bitbucket.org/yt_analysis/yt/commits/ec85468933a7/
Changeset:   ec85468933a7
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 18:39:22
Summary:     Notebooks updated for latest functionality
Affected #:  2 files

diff -r 41e6f4f08ee37a1b4bb8b6fd7c1e8752c7750e66 -r ec85468933a79577112a3878f7e832cd22d9a0b0 doc/source/cookbook/fits_radio_cubes.ipynb
--- a/doc/source/cookbook/fits_radio_cubes.ipynb
+++ b/doc/source/cookbook/fits_radio_cubes.ipynb
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:ded7d47bf5a74c9ea5431a37b6d371a631909d2b95214cd8053617762f62e2e4"
+  "signature": "sha256:2f774139560d94508c2c51b70930d46941d9ceef7228655de32a69634f6c6d83"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -73,14 +73,43 @@
      "cell_type": "markdown",
      "metadata": {},
      "source": [
-      "Note that the x and y axes are in units of \"code length\", which in the case of FITS datasets are equal to the width of one pixel. Currently, the `yt` plotting routines don't understand datasets with non-length units on the axes (such as RA, Dec, velocity, etc.), so it defaults to the pixel scale. This will be changed in a future release. When making plots of FITS data, to see the image coordinates as they are in the file, it is helpful to set the keyword `origin = \"native\"`."
+      "The x and y axes are in units of the image pixel. When making plots of FITS data, to see the image coordinates as they are in the file, it is helpful to set the keyword `origin = \"native\"`. If you want to see the celestial coordinates along the axes, you can import the `PlotWindowWCS` class and feed it the `SlicePlot`. For this to work, the [WCSAxes](http://wcsaxes.readthedocs.org/en/latest/) package needs to be installed."
      ]
     },
     {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from yt.frontends.fits.misc import PlotWindowWCS\n",
+      "wcs_slc = PlotWindowWCS(slc)\n",
+      "wcs_slc.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
-      "We can take slices of this dataset at a few different values along the \"z\" axis (corresponding to the velocity), so let's try a few. First, we'll check what the value along the velocity axis at the domain center is, as well as the range of possible values. This is the third value of each array. "
+      "Generally, it is best to get the plot in the shape you want it before feeding it to `PlotWindowWCS`. Once it looks the way you want, you can save it just like a normal `PlotWindow` plot:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "wcs_slc.save()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "We can also take slices of this dataset at a few different values along the \"z\" axis (corresponding to the velocity), so let's try a few. First, we'll check what the value along the velocity axis at the domain center is, as well as the range of possible values. This is the third value of each array. "
      ]
     },
     {
@@ -147,6 +176,44 @@
      ]
     },
     {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "We can also look at the slices perpendicular to the other axes, which will show us the structure along the velocity axis:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "slc = yt.SlicePlot(ds, \"x\", [\"intensity\"], origin=\"native\", \n",
+      "                   aspect=\"auto\", window_size=(8.0,8.0))\n",
+      "slc.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "slc = yt.SlicePlot(ds, \"y\", [\"intensity\"], origin=\"native\", \n",
+      "                   aspect=\"auto\", window_size=(8.0,8.0))\n",
+      "slc.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "In these cases, we needed to set `aspect=\"auto\"` and explicitly declare a square `window_size` to get a figure that looks good. "
+     ]
+    },
+    {
      "cell_type": "heading",
      "level": 2,
      "metadata": {},
@@ -298,6 +365,78 @@
      "language": "python",
      "metadata": {},
      "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Finally, we can also take an existing [ds9](http://ds9.si.edu/site/Home.html) region and use it to create a \"cut region\" as well, using `ds9_region` (the [pyregion](http://leejjoon.github.io/pyregion/) package needs to be installed for this):"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from yt.frontends.fits.misc import ds9_region"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "For this example we'll create a ds9 region from scratch and load it up:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "region = 'galactic;box(+49:26:35.150,-0:30:04.410,1926.1927\",1483.3701\",0.0)'\n",
+      "box_reg = ds9_region(ds, region)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "This region may now be used to compute derived quantities:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print box_reg.quantities.extrema(\"temperature\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Or in projections:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj = yt.ProjectionPlot(ds, \"z\", [\"temperature\"], origin=\"native\", \n",
+      "                        data_source=box_reg, weight_field=\"ones\") # \"ones\" weights each cell by 1\n",
+      "prj.set_log(\"temperature\", True)\n",
+      "prj.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
     }
    ],
    "metadata": {}

diff -r 41e6f4f08ee37a1b4bb8b6fd7c1e8752c7750e66 -r ec85468933a79577112a3878f7e832cd22d9a0b0 doc/source/cookbook/fits_xray_images.ipynb
--- a/doc/source/cookbook/fits_xray_images.ipynb
+++ b/doc/source/cookbook/fits_xray_images.ipynb
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:564cb1986609d8bb76397a18219974504231b260f912bed483b87c1f896e92ac"
+  "signature": "sha256:51515125ecfe1903e74872ae1594a4184a0045ae1b26b73f0637c84a398c42cd"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -71,19 +71,18 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "ds.index\n",
       "def _counts(field, data):\n",
       "    exposure_time = data.get_field_parameter(\"exposure_time\")\n",
       "    return data[\"flux\"]*data[\"pixel\"]*exposure_time\n",
-      "ds.field_info.add_field(name=\"counts\", function=_counts, units=\"counts\")\n",
+      "ds.add_field(name=\"counts\", function=_counts, units=\"counts\")\n",
       "\n",
       "def _pp(field, data):\n",
       "    return np.sqrt(data[\"counts\"])*data[\"projected_temperature\"]\n",
-      "ds.field_info.add_field(name=\"pseudo_pressure\", function=_pp, units=\"sqrt(counts)*keV\")\n",
+      "ds.add_field(name=\"pseudo_pressure\", function=_pp, units=\"sqrt(counts)*keV\")\n",
       "\n",
       "def _pe(field, data):\n",
       "    return data[\"projected_temperature\"]*data[\"counts\"]**(-1./3.)\n",
-      "ds.field_info.add_field(name=\"pseudo_entropy\", function=_pe, units=\"keV*(counts)**(-1/3)\")"
+      "ds.add_field(name=\"pseudo_entropy\", function=_pe, units=\"keV*(counts)**(-1/3)\")"
      ],
      "language": "python",
      "metadata": {},
@@ -131,6 +130,92 @@
      "outputs": []
     },
     {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "To add the celestial coordinates to the image, we can use `PlotWindowWCS`, if you have the [WCSAxes](http://wcsaxes.readthedocs.org/en/latest/) package installed:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from yt.frontends.fits.misc import PlotWindowWCS\n",
+      "wcs_slc = PlotWindowWCS(slc)\n",
+      "wcs_slc.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Finally, we can also take an existing [ds9](http://ds9.si.edu/site/Home.html) region and use it to create a \"cut region\", using `ds9_region` (the [pyregion](http://leejjoon.github.io/pyregion/) package needs to be installed for this):"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from yt.frontends.fits.misc import ds9_region\n",
+      "reg_file = [\"# Region file format: DS9 version 4.1\\n\",\n",
+      "            \"global color=green dashlist=8 3 width=3 include=1 source=1 fk5\\n\",\n",
+      "            \"circle(15:16:44.817,+7:01:19.62,34.6256\\\")\"]\n",
+      "f = open(\"circle.reg\",\"w\")\n",
+      "f.writelines(reg_file)\n",
+      "f.close()\n",
+      "circle_reg = ds9_region(ds, \"circle.reg\", field_parameters={\"exposure_time\":exposure_time})"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "This region may now be used to compute derived quantities:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print circle_reg.quantities.weighted_average_quantity(\"projected_temperature\", \"counts\")"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Or used in projections:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "prj = yt.ProjectionPlot(ds, \"z\", \n",
+      "                   [\"flux\",\"projected_temperature\",\"pseudo_pressure\",\"pseudo_entropy\"], \n",
+      "                   origin=\"native\", field_parameters={\"exposure_time\":exposure_time},\n",
+      "                   data_source=circle_reg,\n",
+      "                   proj_style=\"sum\")\n",
+      "prj.set_log(\"flux\",True)\n",
+      "prj.set_log(\"pseudo_pressure\",False)\n",
+      "prj.set_log(\"pseudo_entropy\",False)\n",
+      "prj.set_width(250.)\n",
+      "prj.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
      "cell_type": "heading",
      "level": 2,
      "metadata": {},
@@ -159,15 +244,14 @@
      "cell_type": "markdown",
      "metadata": {},
      "source": [
-      "`setup_counts_fields` will take a list of energy bounds (emin, emax) in keV and create a new field from each where the photons in that energy range will be deposited onto the image grid. "
+      "`load` will handle the events file as FITS image files, and will set up a grid using the WCS information in the file. Optionally, the events may be reblocked to a new resolution. by setting the `\"reblock\"` parameter in the `parameters` dictionary in `load`. `\"reblock\"` must be a power of 2. "
      ]
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "ebounds = [(0.1,2.0),(2.0,5.0)]\n",
-      "setup_counts_fields(ebounds)"
+      "ds2 = yt.load(\"xray_fits/acisf05356N003_evt2.fits.gz\", parameters={\"reblock\":2})"
      ],
      "language": "python",
      "metadata": {},
@@ -177,14 +261,15 @@
      "cell_type": "markdown",
      "metadata": {},
      "source": [
-      "`load` will handle the events file as FITS image files, and will set up a grid using the WCS information in the file. Optionally, the events may be reblocked to a new resolution. by setting the `\"reblock\"` parameter in the `parameters` dictionary in `load`. `\"reblock\"` must be a power of 2. "
+      "`setup_counts_fields` will take a list of energy bounds (emin, emax) in keV and create a new field from each where the photons in that energy range will be deposited onto the image grid. "
      ]
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "ds2 = yt.load(\"xray_fits/acisf05356N003_evt2.fits.gz\", parameters={\"reblock\":2})"
+      "ebounds = [(0.1,2.0),(2.0,5.0)]\n",
+      "setup_counts_fields(ds2, ebounds)"
      ],
      "language": "python",
      "metadata": {},


https://bitbucket.org/yt_analysis/yt/commits/3fb307c4736d/
Changeset:   3fb307c4736d
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 20:49:10
Summary:     A few more nifty things for this notebook
Affected #:  1 file

diff -r ec85468933a79577112a3878f7e832cd22d9a0b0 -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 doc/source/cookbook/fits_xray_images.ipynb
--- a/doc/source/cookbook/fits_xray_images.ipynb
+++ b/doc/source/cookbook/fits_xray_images.ipynb
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:51515125ecfe1903e74872ae1594a4184a0045ae1b26b73f0637c84a398c42cd"
+  "signature": "sha256:650e3fc7f66951a5fcdb18332bbc625f6f6e449fc919acd01da01e1fbbf92ee1"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -74,15 +74,15 @@
       "def _counts(field, data):\n",
       "    exposure_time = data.get_field_parameter(\"exposure_time\")\n",
       "    return data[\"flux\"]*data[\"pixel\"]*exposure_time\n",
-      "ds.add_field(name=\"counts\", function=_counts, units=\"counts\")\n",
+      "ds.add_field(name=\"counts\", function=_counts, units=\"counts\", take_log=False)\n",
       "\n",
       "def _pp(field, data):\n",
       "    return np.sqrt(data[\"counts\"])*data[\"projected_temperature\"]\n",
-      "ds.add_field(name=\"pseudo_pressure\", function=_pp, units=\"sqrt(counts)*keV\")\n",
+      "ds.add_field(name=\"pseudo_pressure\", function=_pp, units=\"sqrt(counts)*keV\", take_log=False)\n",
       "\n",
       "def _pe(field, data):\n",
       "    return data[\"projected_temperature\"]*data[\"counts\"]**(-1./3.)\n",
-      "ds.add_field(name=\"pseudo_entropy\", function=_pe, units=\"keV*(counts)**(-1/3)\")"
+      "ds.add_field(name=\"pseudo_entropy\", function=_pe, units=\"keV*(counts)**(-1/3)\", take_log=False)"
      ],
      "language": "python",
      "metadata": {},
@@ -152,6 +152,66 @@
      "cell_type": "markdown",
      "metadata": {},
      "source": [
+      "We can make use of yt's facilities for profile plotting as well."
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "v, c = ds.find_max(\"flux\") # Find the maxmimum flux and its center\n",
+      "my_sphere = ds.sphere(c, (100.,\"code_length\")) # Radius of 150 pixels\n",
+      "my_sphere.set_field_parameter(\"exposure_time\", exposure_time)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Such as a radial profile plot:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "radial_profile = yt.ProfilePlot(my_sphere, \"radius\", \n",
+      "                                [\"counts\",\"pseudo_pressure\",\"pseudo_entropy\"], \n",
+      "                                n_bins=50, weight_field=\"ones\")\n",
+      "radial_profile.set_log(\"counts\", True)\n",
+      "radial_profile.set_log(\"pseudo_pressure\", True)\n",
+      "radial_profile.set_log(\"pseudo_entropy\", True)\n",
+      "radial_profile.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Or a phase plot:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "phase_plot = yt.PhasePlot(my_sphere, \"pseudo_pressure\", \"pseudo_entropy\", [\"counts\"], weight_field=None)\n",
+      "phase_plot.show()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
       "Finally, we can also take an existing [ds9](http://ds9.si.edu/site/Home.html) region and use it to create a \"cut region\", using `ds9_region` (the [pyregion](http://leejjoon.github.io/pyregion/) package needs to be installed for this):"
      ]
     },


https://bitbucket.org/yt_analysis/yt/commits/c91dfb4837a8/
Changeset:   c91dfb4837a8
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 20:52:15
Summary:     Merge
Affected #:  138 files

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/install_script.sh
--- a/doc/install_script.sh
+++ b/doc/install_script.sh
@@ -590,7 +590,7 @@
 LAPACK='lapack-3.4.2'
 PNG=libpng-1.6.3
 MATPLOTLIB='matplotlib-1.3.0'
-MERCURIAL='mercurial-2.8'
+MERCURIAL='mercurial-3.0'
 NOSE='nose-1.3.0'
 NUMPY='numpy-1.7.1'
 PYTHON_HGLIB='python-hglib-1.0'
@@ -619,7 +619,7 @@
 echo '8770214491e31f0a7a3efaade90eee7b0eb20a8a6ab635c5f854d78263f59a1849133c14ef5123d01023f0110cbb9fc6f818da053c01277914ae81473430a952  lapack-3.4.2.tar.gz' > lapack-3.4.2.tar.gz.sha512
 echo '887582e5a22e4cde338aa8fec7a89f6dd31f2f02b8842735f00f970f64582333fa03401cea6d01704083403c7e8b7ebc26655468ce930165673b33efa4bcd586  libpng-1.6.3.tar.gz' > libpng-1.6.3.tar.gz.sha512
 echo '990e3a155ca7a9d329c41a43b44a9625f717205e81157c668a8f3f2ad5459ed3fed8c9bd85e7f81c509e0628d2192a262d4aa30c8bfc348bb67ed60a0362505a  matplotlib-1.3.0.tar.gz' > matplotlib-1.3.0.tar.gz.sha512
-echo 'b08dcd746728d89f1f96036f39df1608fad0ff863ae48fe12424b1645936ebbf59b9068b93fe3c7cfd2036db046df3dc814119f89a827bd5f008d32f323d45a8  mercurial-2.8.tar.gz' > mercurial-2.8.tar.gz.sha512
+echo '8cd387ea0d74d5ed01b58d5ef8e3fb408d4b05f7deb45a02e34fbb931fd920aafbfcb3a9b52a027ebcdb562837198637a0e51f2121c94e0fcf7f7d8c016f5342  mercurial-3.0.tar.gz' > mercurial-3.0.tar.gz.sha512
 echo 'a3b8060e415560a868599224449a3af636d24a060f1381990b175dcd12f30249edd181179d23aea06b0c755ff3dc821b7a15ed8840f7855530479587d4d814f4  nose-1.3.0.tar.gz' > nose-1.3.0.tar.gz.sha512
 echo 'd58177f3971b6d07baf6f81a2088ba371c7e43ea64ee7ada261da97c6d725b4bd4927122ac373c55383254e4e31691939276dab08a79a238bfa55172a3eff684  numpy-1.7.1.tar.gz' > numpy-1.7.1.tar.gz.sha512
 echo '9c0a61299779aff613131aaabbc255c8648f0fa7ab1806af53f19fbdcece0c8a68ddca7880d25b926d67ff1b9201954b207919fb09f6a290acb078e8bbed7b68  python-hglib-1.0.tar.gz' > python-hglib-1.0.tar.gz.sha512

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/aligned_cutting_plane.py
--- a/doc/source/cookbook/aligned_cutting_plane.py
+++ b/doc/source/cookbook/aligned_cutting_plane.py
@@ -1,18 +1,18 @@
-from yt.mods import *
+import yt
 
 # Load the dataset.
-pf = load("IsolatedGalaxy/galaxy0030/galaxy0030")
+ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
 
 # Create a 1 kpc radius sphere, centered on the max density.  Note that this
 # sphere is very small compared to the size of our final plot, and it has a
 # non-axially aligned L vector.
-sp = pf.sphere("center", (15.0, "kpc"))
+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: %s" % (L)
+print "Angular momentum vector: {0}".format(L)
 
 # Create an OffAxisSlicePlot on the object with the L vector as its normal
-p = OffAxisSlicePlot(pf, L, "density", sp.center, (25, "kpc"))
+p = yt.OffAxisSlicePlot(ds, L, "density", sp.center, (25, "kpc"))
 p.save()

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/amrkdtree_downsampling.py
--- a/doc/source/cookbook/amrkdtree_downsampling.py
+++ b/doc/source/cookbook/amrkdtree_downsampling.py
@@ -1,26 +1,28 @@
-## Using AMRKDTree Homogenized Volumes to examine large datasets at lower resolution.
+# Using AMRKDTree Homogenized Volumes to examine large datasets
+# at lower resolution.
 
 # In this example we will show how to use the AMRKDTree to take a simulation
 # with 8 levels of refinement and only use levels 0-3 to render the dataset.
 
 # We begin by loading up yt, and importing the AMRKDTree
+import numpy as np
 
-from yt.mods import *
+import yt
 from yt.utilities.amr_kdtree.api import AMRKDTree
 
 # Load up a data and print out the maximum refinement level
-pf = load('IsolatedGalaxy/galaxy0030/galaxy0030')
+ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
 
-kd = AMRKDTree(pf)
+kd = AMRKDTree(ds)
 # Print out the total volume of all the bricks
 print kd.count_volume()
 # Print out the number of cells
 print kd.count_cells()
 
-tf = ColorTransferFunction((-30, -22))
-cam = pf.h.camera([0.5, 0.5, 0.5], [0.2, 0.3, 0.4], 0.10, 256,
-                 tf, volume=kd)
-tf.add_layers(4, 0.01, col_bounds = [-27.5,-25.5], colormap = 'RdBu_r')
+tf = yt.ColorTransferFunction((-30, -22))
+cam = ds.h.camera([0.5, 0.5, 0.5], [0.2, 0.3, 0.4], 0.10, 256,
+                  tf, volume=kd)
+tf.add_layers(4, 0.01, col_bounds=[-27.5, -25.5], colormap='RdBu_r')
 cam.snapshot("v1.png", clip_ratio=6.0)
 
 # This rendering is okay, but lets say I'd like to improve it, and I don't want
@@ -28,7 +30,7 @@
 # generate a low resolution version of the AMRKDTree and pass that in to the
 # camera.  We do this by specifying a maximum refinement level of 3.
 
-kd_low_res = AMRKDTree(pf, l_max=3)
+kd_low_res = AMRKDTree(ds, max_level=3)
 print kd_low_res.count_volume()
 print kd_low_res.count_cells()
 
@@ -42,21 +44,21 @@
 # rendering until we find something we like.
 
 tf.clear()
-tf.add_layers(4, 0.01, col_bounds = [-27.5,-25.5],
-        alpha=np.ones(4,dtype='float64'), colormap = 'RdBu_r')
+tf.add_layers(4, 0.01, col_bounds=[-27.5, -25.5],
+              alpha=np.ones(4, dtype='float64'), colormap='RdBu_r')
 cam.snapshot("v2.png", clip_ratio=6.0)
 
 # This looks better.  Now let's try turning on opacity.
 
-tf.grey_opacity=True
+tf.grey_opacity = True
 cam.snapshot("v4.png", clip_ratio=6.0)
 
 # That seemed to pick out som interesting structures.  Now let's bump up the
 # opacity.
 
 tf.clear()
-tf.add_layers(4, 0.01, col_bounds = [-27.5,-25.5],
-        alpha=10.0*np.ones(4,dtype='float64'), colormap = 'RdBu_r')
+tf.add_layers(4, 0.01, col_bounds=[-27.5, -25.5],
+              alpha=10.0 * np.ones(4, dtype='float64'), colormap='RdBu_r')
 cam.snapshot("v3.png", clip_ratio=6.0)
 
 # This looks pretty good, now lets go back to the full resolution AMRKDTree
@@ -65,4 +67,3 @@
 cam.snapshot("v4.png", clip_ratio=6.0)
 
 # This looks great!
-

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/average_value.py
--- a/doc/source/cookbook/average_value.py
+++ b/doc/source/cookbook/average_value.py
@@ -1,12 +1,12 @@
-from yt.mods import *
+import yt
 
-pf = load("IsolatedGalaxy/galaxy0030/galaxy0030") # load data
+ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")  # load data
 
 field = "temperature"  # The field to average
-weight = "cell_mass" # The weight for the average
+weight = "cell_mass"  # The weight for the average
 
-dd = pf.h.all_data() # This is a region describing the entire box,
-                     # but note it doesn't read anything in yet!
+dd = ds.h.all_data()  # This is a region describing the entire box,
+                      # but note it doesn't read anything in yet!
 # We now use our 'quantities' call to get the average quantity
 average_value = dd.quantities["WeightedAverageQuantity"](field, weight)
 

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/boolean_data_objects.py
--- a/doc/source/cookbook/boolean_data_objects.py
+++ b/doc/source/cookbook/boolean_data_objects.py
@@ -1,23 +1,23 @@
-from yt.mods import * # set up our namespace
+import yt
 
-pf = load("Enzo_64/DD0043/data0043") # load data
+ds = yt.load("Enzo_64/DD0043/data0043")  # load data
 # Make a few data ojbects to start.
-re1 = pf.region([0.5, 0.5, 0.5], [0.4, 0.4, 0.4], [0.6, 0.6, 0.6])
-re2 = pf.region([0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [0.6, 0.6, 0.6])
-sp1 = pf.sphere([0.5, 0.5, 0.5], 0.05)
-sp2 = pf.sphere([0.1, 0.2, 0.3], 0.1)
+re1 = ds.region([0.5, 0.5, 0.5], [0.4, 0.4, 0.4], [0.6, 0.6, 0.6])
+re2 = ds.region([0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [0.6, 0.6, 0.6])
+sp1 = ds.sphere([0.5, 0.5, 0.5], 0.05)
+sp2 = ds.sphere([0.1, 0.2, 0.3], 0.1)
 # The "AND" operator. This will make a region identical to re2.
-bool1 = pf.boolean([re1, "AND", re2])
+bool1 = ds.boolean([re1, "AND", re2])
 xp = bool1["particle_position_x"]
 # The "OR" operator. This will make a region identical to re1.
-bool2 = pf.boolean([re1, "OR", re2])
+bool2 = ds.boolean([re1, "OR", re2])
 # The "NOT" operator. This will make a region like re1, but with the corner
 # that re2 covers cut out.
-bool3 = pf.boolean([re1, "NOT", re2])
+bool3 = ds.boolean([re1, "NOT", re2])
 # Disjoint regions can be combined with the "OR" operator.
-bool4 = pf.boolean([sp1, "OR", sp2])
+bool4 = ds.boolean([sp1, "OR", sp2])
 # Find oddly-shaped overlapping regions.
-bool5 = pf.boolean([re2, "AND", sp1])
+bool5 = ds.boolean([re2, "AND", sp1])
 # Nested logic with parentheses.
 # This is re1 with the oddly-shaped region cut out.
-bool6 = pf.boolean([re1, "NOT", "(", re1, "AND", sp1, ")"])
+bool6 = ds.boolean([re1, "NOT", "(", re1, "AND", sp1, ")"])

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/camera_movement.py
--- a/doc/source/cookbook/camera_movement.py
+++ b/doc/source/cookbook/camera_movement.py
@@ -1,43 +1,43 @@
-from yt.mods import * # set up our namespace
+import numpy as np
+
+import yt
 
 # Follow the simple_volume_rendering cookbook for the first part of this.
-pf = load("IsolatedGalaxy/galaxy0030/galaxy0030") # load data
-dd = pf.h.all_data()
-mi, ma = dd.quantities["Extrema"]("density")[0]
+ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")  # load data
+dd = ds.all_data()
+mi, ma = dd.quantities["Extrema"]("density")
 
 # Set up transfer function
-tf = ColorTransferFunction((np.log10(mi), np.log10(ma)))
+tf = yt.ColorTransferFunction((np.log10(mi), np.log10(ma)))
 tf.add_layers(6, w=0.05)
 
 # Set up camera paramters
-c = [0.5, 0.5, 0.5] # Center
-L = [1, 1, 1] # Normal Vector
-W = 1.0 # Width
-Nvec = 512 # Pixels on a side
+c = [0.5, 0.5, 0.5]  # Center
+L = [1, 1, 1]  # Normal Vector
+W = 1.0  # Width
+Nvec = 512  # Pixels on a side
 
 # Specify a north vector, which helps with rotations.
-north_vector = [0.,0.,1.]
+north_vector = [0., 0., 1.]
 
 # Find the maximum density location, store it in max_c
-v,max_c = pf.h.find_max('density')
+v, max_c = ds.find_max('density')
 
 # Initialize the Camera
-cam = pf.h.camera(c, L, W, (Nvec,Nvec), tf, north_vector=north_vector)
+cam = ds.camera(c, L, W, (Nvec, Nvec), tf, north_vector=north_vector)
 frame = 0
 
 # Do a rotation over 5 frames
-for i, snapshot in enumerate(cam.rotation(np.pi, 5, clip_ratio = 8.0)):
+for i, snapshot in enumerate(cam.rotation(np.pi, 5, clip_ratio=8.0)):
     snapshot.write_png('camera_movement_%04i.png' % frame)
     frame += 1
 
 # Move to the maximum density location over 5 frames
-for i, snapshot in enumerate(cam.move_to(max_c, 5, clip_ratio = 8.0)):
+for i, snapshot in enumerate(cam.move_to(max_c, 5, clip_ratio=8.0)):
     snapshot.write_png('camera_movement_%04i.png' % frame)
     frame += 1
 
 # Zoom in by a factor of 10 over 5 frames
-for i, snapshot in enumerate(cam.zoomin(10.0, 5, clip_ratio = 8.0)):
+for i, snapshot in enumerate(cam.zoomin(10.0, 5, clip_ratio=8.0)):
     snapshot.write_png('camera_movement_%04i.png' % frame)
-    frame += 1
-
-
+    frame += 1
\ No newline at end of file

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/contours_on_slice.py
--- a/doc/source/cookbook/contours_on_slice.py
+++ b/doc/source/cookbook/contours_on_slice.py
@@ -1,13 +1,13 @@
-from yt.mods import * # set up our namespace
+import yt
 
 # first add density contours on a density slice
-pf = load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150") # load data
-p = SlicePlot(pf, "x", "density")
+pf = yt.load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150")  # load data
+p = yt.SlicePlot(pf, "x", "density")
 p.annotate_contour("density")
 p.save()
 
 # then add temperature contours on the same densty slice
-pf = load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150") # load data
-p = SlicePlot(pf, "x", "density")
+pf = yt.load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150")  # load data
+p = yt.SlicePlot(pf, "x", "density")
 p.annotate_contour("temperature")
 p.save(str(pf)+'_T_contour')

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/extract_fixed_resolution_data.py
--- a/doc/source/cookbook/extract_fixed_resolution_data.py
+++ b/doc/source/cookbook/extract_fixed_resolution_data.py
@@ -1,25 +1,25 @@
-from yt.mods import *
+import yt
 
 # For this example we will use h5py to write to our output file.
 import h5py
 
-pf = load("IsolatedGalaxy/galaxy0030/galaxy0030")
+ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
 
 level = 2
-dims = pf.domain_dimensions * pf.refine_by**level
+dims = ds.domain_dimensions * ds.refine_by**level
 
 # Now, we construct an object that describes the data region and structure we
 # want
-cube = pf.covering_grid(2, # The level we are willing to extract to; higher
-                             # levels than this will not contribute to the data!
-                          left_edge=[0.0, 0.0, 0.0], 
-                          # And any fields to preload (this is optional!)
-                          dims = dims,
-                          fields=["density"])
+cube = ds.covering_grid(2,  # The level we are willing to extract to; higher
+                            # levels than this will not contribute to the data!
+                        left_edge=[0.0, 0.0, 0.0],
+                        # And any fields to preload (this is optional!)
+                        dims=dims,
+                        fields=["density"])
 
 # Now we open our output file using h5py
 # Note that we open with 'w' which will overwrite existing files!
-f = h5py.File("my_data.h5", "w") 
+f = h5py.File("my_data.h5", "w")
 
 # We create a dataset at the root note, calling it density...
 f.create_dataset("/density", data=cube["density"])

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/find_clumps.py
--- a/doc/source/cookbook/find_clumps.py
+++ b/doc/source/cookbook/find_clumps.py
@@ -1,26 +1,30 @@
-# set up our namespace
-from yt.mods import * 
-from yt.analysis_modules.level_sets.api import *
+import numpy as np
 
-fn = "IsolatedGalaxy/galaxy0030/galaxy0030" # parameter file to load
-field = "density" # this is the field we look for contours over -- we could do
-                  # this over anything.  Other common choices are 'AveragedDensity'
-                  # and 'Dark_Matter_Density'.
-step = 2.0 # This is the multiplicative interval between contours.
+import yt
+from yt.analysis_modules.level_sets.api import (Clump, find_clumps,
+                                                get_lowest_clumps)
 
-pf = load(fn) # load data
+fn = "IsolatedGalaxy/galaxy0030/galaxy0030"  # parameter file to load
+# this is the field we look for contours over -- we could do
+# this over anything.  Other common choices are 'AveragedDensity'
+# and 'Dark_Matter_Density'.
+field = "density"
+
+step = 2.0  # This is the multiplicative interval between contours.
+
+ds = yt.load(fn)  # load data
 
 # We want to find clumps over the entire dataset, so we'll just grab the whole
 # thing!  This is a convenience parameter that prepares an object that covers
 # the whole domain.  Note, though, that it will load on demand and not before!
-data_source = pf.disk([0.5, 0.5, 0.5], [0., 0., 1.], 
-                        8./pf.units['kpc'], 1./pf.units['kpc'])
+data_source = ds.disk([0.5, 0.5, 0.5], [0., 0., 1.],
+                      (8., 'kpc'), (1., 'kpc'))
 
 # Now we set some sane min/max values between which we want to find contours.
 # This is how we tell the clump finder what to look for -- it won't look for
 # contours connected below or above these threshold values.
-c_min = 10**np.floor(np.log10(data_source[field]).min()  )
-c_max = 10**np.floor(np.log10(data_source[field]).max()+1)
+c_min = 10**np.floor(np.log10(data_source[field]).min())
+c_max = 10**np.floor(np.log10(data_source[field]).max() + 1)
 
 # keep only clumps with at least 20 cells
 function = 'self.data[\'%s\'].size > 20' % field
@@ -38,13 +42,13 @@
 # As it goes, it appends the information about all the sub-clumps to the
 # master-clump.  Among different ways we can examine it, there's a convenience
 # function for outputting the full index to a file.
-f = open('%s_clump_index.txt' % pf,'w')
-amods.level_sets.write_clump_index(master_clump,0,f)
+f = open('%s_clump_index.txt' % ds, 'w')
+yt.amods.level_sets.write_clump_index(master_clump, 0, f)
 f.close()
 
 # We can also output some handy information, as well.
-f = open('%s_clumps.txt' % pf,'w')
-amods.level_sets.write_clumps(master_clump,0,f)
+f = open('%s_clumps.txt' % ds, 'w')
+yt.amods.level_sets.write_clumps(master_clump, 0, f)
 f.close()
 
 # We can traverse the clump index to get a list of all of the 'leaf' clumps
@@ -52,7 +56,7 @@
 
 # If you'd like to visualize these clumps, a list of clumps can be supplied to
 # the "clumps" callback on a plot.  First, we create a projection plot:
-prj = ProjectionPlot(pf, 2, field, center='c', width=(20,'kpc'))
+prj = yt.ProjectionPlot(ds, 2, field, center='c', width=(20, 'kpc'))
 
 # Next we annotate the plot with contours on the borders of the clumps
 prj.annotate_clumps(leaf_clumps)
@@ -62,7 +66,7 @@
 
 # We can also save the clump object to disk to read in later so we don't have
 # to spend a lot of time regenerating the clump objects.
-pf.h.save_object(master_clump, 'My_clumps')
+ds.h.save_object(master_clump, 'My_clumps')
 
 # Later, we can read in the clump object like so,
-master_clump = pf.h.load_object('My_clumps')
+master_clump = ds.load_object('My_clumps')

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/fit_spectrum.py
--- a/doc/source/cookbook/fit_spectrum.py
+++ b/doc/source/cookbook/fit_spectrum.py
@@ -1,25 +1,19 @@
-import os
-import sys
-import h5py
+import yt
+from yt.analysis_modules.cosmological_observation.light_ray.api import LightRay
+from yt.analysis_modules.api import AbsorptionSpectrum
+from yt.analysis_modules.absorption_spectrum.api import generate_total_fit
 
-from yt.mods import *
-from yt.analysis_modules.cosmological_observation.light_ray.api import \
-     LightRay
-from yt.analysis_modules.api import AbsorptionSpectrum
-from yt.analysis_modules.absorption_spectrum.api import \
-        generate_total_fit
+# Define and add a field to simulate OVI based on a constant relationship to HI
+def _OVI_NumberDensity(field, data):
+    return data['HI_NumberDensity']
 
-# Define and add a field to simulate OVI based on
-# a constant relationship to HI
 
-def _OVI_NumberDensity(field,data):
-    return data['HI_NumberDensity']
 def _convertOVI(data):
     return 4.9E-4*.2
 
-add_field('my_OVI_NumberDensity',
-        function=_OVI_NumberDensity,
-        convert_function=_convertOVI)
+yt.add_field('my_OVI_NumberDensity',
+             function=_OVI_NumberDensity,
+             convert_function=_convertOVI)
 
 
 # Define species andi associated parameters to add to continuum
@@ -29,33 +23,33 @@
 # (as in the OVI doublet), 'numLines' will be equal to the number
 # of lines, and f,gamma, and wavelength will have multiple values.
 
-HI_parameters = {'name':'HI',
-        'field' : 'HI_NumberDensity',
-        'f': [.4164],
-        'Gamma':[6.265E8],
-        'wavelength':[1215.67],
-        'mass': 1.00794,
-        'numLines':1,
-        'maxN': 1E22, 'minN':1E11,
-        'maxb': 300, 'minb':1,
-        'maxz': 6, 'minz':0,
-        'init_b':30,
-        'init_N':1E14}
+HI_parameters = {'name': 'HI',
+                 'field': 'HI_NumberDensity',
+                 'f': [.4164],
+                 'Gamma': [6.265E8],
+                 'wavelength': [1215.67],
+                 'mass': 1.00794,
+                 'numLines': 1,
+                 'maxN': 1E22, 'minN': 1E11,
+                 'maxb': 300, 'minb': 1,
+                 'maxz': 6, 'minz': 0,
+                 'init_b': 30,
+                 'init_N': 1E14}
 
-OVI_parameters = {'name':'OVI',
-        'field' : 'my_OVI_NumberDensity',
-        'f':[.1325,.06580],
-        'Gamma':[4.148E8,4.076E8],
-        'wavelength':[1031.9261,1037.6167],
-        'mass': 15.9994,
-        'numLines':2,
-        'maxN':1E17,'minN':1E11,
-        'maxb':300, 'minb':1,
-        'maxz':6, 'minz':0,
-        'init_b':20,
-        'init_N':1E12}
+OVI_parameters = {'name': 'OVI',
+                  'field': 'my_OVI_NumberDensity',
+                  'f': [.1325, .06580],
+                  'Gamma': [4.148E8, 4.076E8],
+                  'wavelength': [1031.9261, 1037.6167],
+                  'mass': 15.9994,
+                  'numLines': 2,
+                  'maxN': 1E17, 'minN': 1E11,
+                  'maxb': 300, 'minb': 1,
+                  'maxz': 6, 'minz': 0,
+                  'init_b': 20,
+                  'init_N': 1E12}
 
-species_dicts = {'HI':HI_parameters,'OVI':OVI_parameters}
+species_dicts = {'HI': HI_parameters, 'OVI': OVI_parameters}
 
 # Create a LightRay object extending from z = 0 to z = 0.1
 # and use only the redshift dumps.
@@ -63,7 +57,7 @@
               'Enzo', 0.0, 0.1,
               use_minimum_datasets=True,
               time_data=False
-            )
+              )
 
 # Get all fields that need to be added to the light ray
 fields = ['temperature']
@@ -80,34 +74,32 @@
                   get_los_velocity=True,
                   njobs=-1)
 
-# Create an AbsorptionSpectrum object extending from 
+# Create an AbsorptionSpectrum object extending from
 # lambda = 900 to lambda = 1800, with 10000 pixels
 sp = AbsorptionSpectrum(900.0, 1400.0, 50000)
 
 # Iterate over species
-for s,params in species_dicts.iteritems():
-
-    #Iterate over transitions for a single species
+for s, params in species_dicts.iteritems():
+    # Iterate over transitions for a single species
     for i in range(params['numLines']):
-
-        #Add the lines to the spectrum
-        sp.add_line(s, params['field'], 
-                params['wavelength'][i], params['f'][i],
-                params['Gamma'][i], params['mass'], 
-                label_threshold=1.e10)
+        # Add the lines to the spectrum
+        sp.add_line(s, params['field'],
+                    params['wavelength'][i], params['f'][i],
+                    params['Gamma'][i], params['mass'],
+                    label_threshold=1.e10)
 
 
 # Make and save spectrum
-wavelength, flux = sp.make_spectrum('lightray.h5', 
-        output_file='spectrum.h5',
-        line_list_file='lines.txt',
-        use_peculiar_velocity=True)
+wavelength, flux = sp.make_spectrum('lightray.h5',
+                                    output_file='spectrum.h5',
+                                    line_list_file='lines.txt',
+                                    use_peculiar_velocity=True)
 
 
-#Define order to fit species in
-order_fits = ['OVI','HI']
+# Define order to fit species in
+order_fits = ['OVI', 'HI']
 
 # Fit spectrum and save fit
 fitted_lines, fitted_flux = generate_total_fit(wavelength,
-            flux, order_fits, species_dicts, 
-            output_file='spectrum_fit.h5')
+                                               flux, order_fits, species_dicts,
+                                               output_file='spectrum_fit.h5')

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/free_free_field.py
--- a/doc/source/cookbook/free_free_field.py
+++ b/doc/source/cookbook/free_free_field.py
@@ -1,40 +1,42 @@
-from yt.mods import *
-from yt.utilities.physical_constants import mp # Need to grab the proton mass from the
-                                               # constants database
+import numpy as np
+import yt
+# Need to grab the proton mass from the constants database
+from yt.utilities.physical_constants import mp
 
 # Define the emission field
 
-keVtoerg = 1.602e-9 # Convert energy in keV to energy in erg
-KtokeV = 8.617e-08 # Convert degrees Kelvin to degrees keV
+keVtoerg = 1.602e-9  # Convert energy in keV to energy in erg
+KtokeV = 8.617e-08  # Convert degrees Kelvin to degrees keV
 sqrt3 = np.sqrt(3.)
-expgamma = 1.78107241799 # Exponential of Euler's constant
+expgamma = 1.78107241799  # Exponential of Euler's constant
 
-def _FreeFree_Emission(field, data) :
 
-    if data.has_field_parameter("Z") :
+def _FreeFree_Emission(field, data):
+
+    if data.has_field_parameter("Z"):
         Z = data.get_field_parameter("Z")
-    else :
-        Z = 1.077 # Primordial H/He plasma
+    else:
+        Z = 1.077  # Primordial H/He plasma
 
-    if data.has_field_parameter("mue") :
+    if data.has_field_parameter("mue"):
         mue = data.get_field_parameter("mue")
-    else :
-        mue = 1./0.875 # Primordial H/He plasma
+    else:
+        mue = 1./0.875  # Primordial H/He plasma
 
-    if data.has_field_parameter("mui") :
+    if data.has_field_parameter("mui"):
         mui = data.get_field_parameter("mui")
-    else :
-        mui = 1./0.8125 # Primordial H/He plasma
+    else:
+        mui = 1./0.8125  # Primordial H/He plasma
 
-    if data.has_field_parameter("Ephoton") :
+    if data.has_field_parameter("Ephoton"):
         Ephoton = data.get_field_parameter("Ephoton")
-    else :
-        Ephoton = 1.0 # in keV
+    else:
+        Ephoton = 1.0  # in keV
 
-    if data.has_field_parameter("photon_emission") :
+    if data.has_field_parameter("photon_emission"):
         photon_emission = data.get_field_parameter("photon_emission")
-    else :
-        photon_emission = False # Flag for energy or photon emission
+    else:
+        photon_emission = False  # Flag for energy or photon emission
 
     n_e = data["density"]/(mue*mp)
     n_i = data["density"]/(mui*mp)
@@ -50,24 +52,25 @@
     eps_E = 1.64e-20*Z*Z*n_e*n_i/np.sqrt(data["temperature"]) * \
         np.exp(-Ephoton/kT)*g_ff
 
-    if photon_emission: eps_E /= (Ephoton*keVtoerg)
+    if photon_emission:
+        eps_E /= (Ephoton*keVtoerg)
 
     return eps_E
 
-add_field("FreeFree_Emission", function=_FreeFree_Emission)
+yt.add_field("FreeFree_Emission", function=_FreeFree_Emission)
 
 # Define the luminosity derived quantity
-
-def _FreeFreeLuminosity(data) :
+def _FreeFreeLuminosity(data):
     return (data["FreeFree_Emission"]*data["cell_volume"]).sum()
 
-def _combFreeFreeLuminosity(data, luminosity) :
+
+def _combFreeFreeLuminosity(data, luminosity):
     return luminosity.sum()
 
-add_quantity("FreeFree_Luminosity", function=_FreeFreeLuminosity,
-             combine_function=_combFreeFreeLuminosity, n_ret = 1)
+yt.add_quantity("FreeFree_Luminosity", function=_FreeFreeLuminosity,
+                combine_function=_combFreeFreeLuminosity, n_ret=1)
 
-pf = load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150")
+pf = yt.load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150")
 
 sphere = pf.sphere(pf.domain_center, (100., "kpc"))
 
@@ -75,8 +78,8 @@
 
 print "L_E (1 keV, primordial) = ", sphere.quantities["FreeFree_Luminosity"]()
 
-# The defaults for the field assume a H/He primordial plasma. Let's set the appropriate
-# parameters for a pure hydrogen plasma.
+# The defaults for the field assume a H/He primordial plasma.
+# Let's set the appropriate parameters for a pure hydrogen plasma.
 
 sphere.set_field_parameter("mue", 1.0)
 sphere.set_field_parameter("mui", 1.0)
@@ -90,10 +93,9 @@
 
 print "L_E (10 keV, pure hydrogen) = ", sphere.quantities["FreeFree_Luminosity"]()
 
-# Finally, let's set the flag for photon emission, to get the total number of photons
-# emitted at this energy:
+# Finally, let's set the flag for photon emission, to get the total number
+# of photons emitted at this energy:
 
 sphere.set_field_parameter("photon_emission", True)
 
 print "L_ph (10 keV, pure hydrogen) = ", sphere.quantities["FreeFree_Luminosity"]()
-

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/global_phase_plots.py
--- a/doc/source/cookbook/global_phase_plots.py
+++ b/doc/source/cookbook/global_phase_plots.py
@@ -1,14 +1,14 @@
-from yt.mods import * # set up our namespace
+import yt
 
 # load the dataset
-pf = load("IsolatedGalaxy/galaxy0030/galaxy0030")
+ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")
 
 # This is an object that describes the entire box
-ad = pf.h.all_data()
+ad = ds.h.all_data()
 
-# We plot the average VelocityMagnitude (mass-weighted) in our object 
+# We plot the average VelocityMagnitude (mass-weighted) in our object
 # as a function of Density and temperature
-plot = PhasePlot(ad, "density","temperature","velocity_magnitude")
+plot = yt.PhasePlot(ad, "density", "temperature", "velocity_magnitude")
 
 # save the plot
 plot.save()

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/halo_finding.py
--- a/doc/source/cookbook/halo_finding.py
+++ b/doc/source/cookbook/halo_finding.py
@@ -2,9 +2,9 @@
 This script shows the simplest way of getting halo information.  For more
 information, see :ref:`halo_finding`.
 """
-from yt.mods import * # set up our namespace
+import yt
 
-pf = load("Enzo_64/DD0043/data0043")
+ds = yt.load("Enzo_64/DD0043/data0043")
 
-halos = HaloFinder(pf)
-halos.write_out("%s_halos.txt" % pf)
+halos = yt.HaloFinder(ds)
+halos.write_out("%s_halos.txt" % ds)

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/hse_field.py
--- a/doc/source/cookbook/hse_field.py
+++ b/doc/source/cookbook/hse_field.py
@@ -1,121 +1,134 @@
-from yt.mods import *
+import numpy as np
+import yt
 
-# Define the components of the gravitational acceleration vector field by taking the
-# gradient of the gravitational potential
+# Define the components of the gravitational acceleration vector field by
+# taking the gradient of the gravitational potential
 
-def _Grav_Accel_x(field, data) :
+
+def _Grav_Accel_x(field, data):
 
     # We need to set up stencils
 
-    sl_left = slice(None,-2,None)
-    sl_right = slice(2,None,None)
+    sl_left = slice(None, -2, None)
+    sl_right = slice(2, None, None)
     div_fac = 2.0
 
     dx = div_fac * data['dx'].flat[0]
 
-    gx  = data["Grav_Potential"][sl_right,1:-1,1:-1]/dx
-    gx -= data["Grav_Potential"][sl_left, 1:-1,1:-1]/dx
+    gx = data["gravitational_potential"][sl_right, 1:-1, 1:-1]/dx
+    gx -= data["gravitational_potential"][sl_left, 1:-1, 1:-1]/dx
 
-    new_field = np.zeros(data["Grav_Potential"].shape, dtype='float64')
-    new_field[1:-1,1:-1,1:-1] = -gx
+    new_field = np.zeros(data["gravitational_potential"].shape,
+                         dtype='float64')
+    new_field[1:-1, 1:-1, 1:-1] = -gx
 
     return new_field
 
-def _Grav_Accel_y(field, data) :
+
+def _Grav_Accel_y(field, data):
 
     # We need to set up stencils
 
-    sl_left = slice(None,-2,None)
-    sl_right = slice(2,None,None)
+    sl_left = slice(None, -2, None)
+    sl_right = slice(2, None, None)
     div_fac = 2.0
 
     dy = div_fac * data['dy'].flat[0]
 
-    gy  = data["Grav_Potential"][1:-1,sl_right,1:-1]/dy
-    gy -= data["Grav_Potential"][1:-1,sl_left ,1:-1]/dy
+    gy = data["gravitational_potential"][1:-1, sl_right, 1:-1]/dy
+    gy -= data["gravitational_potential"][1:-1, sl_left, 1:-1]/dy
 
-    new_field = np.zeros(data["Grav_Potential"].shape, dtype='float64')
-    new_field[1:-1,1:-1,1:-1] = -gy
+    new_field = np.zeros(data["gravitational_potential"].shape,
+                         dtype='float64')
+    new_field[1:-1, 1:-1, 1:-1] = -gy
 
     return new_field
 
-def _Grav_Accel_z(field, data) :
+
+def _Grav_Accel_z(field, data):
 
     # We need to set up stencils
 
-    sl_left = slice(None,-2,None)
-    sl_right = slice(2,None,None)
+    sl_left = slice(None, -2, None)
+    sl_right = slice(2, None, None)
     div_fac = 2.0
 
     dz = div_fac * data['dz'].flat[0]
 
-    gz  = data["Grav_Potential"][1:-1,1:-1,sl_right]/dz
-    gz -= data["Grav_Potential"][1:-1,1:-1,sl_left ]/dz
+    gz = data["gravitational_potential"][1:-1, 1:-1, sl_right]/dz
+    gz -= data["gravitational_potential"][1:-1, 1:-1, sl_left]/dz
 
-    new_field = np.zeros(data["Grav_Potential"].shape, dtype='float64')
-    new_field[1:-1,1:-1,1:-1] = -gz
+    new_field = np.zeros(data["gravitational_potential"].shape,
+                         dtype='float64')
+    new_field[1:-1, 1:-1, 1:-1] = -gz
 
     return new_field
 
+
 # Define the components of the pressure gradient field
 
-def _Grad_Pressure_x(field, data) :
+
+def _Grad_Pressure_x(field, data):
 
     # We need to set up stencils
 
-    sl_left = slice(None,-2,None)
-    sl_right = slice(2,None,None)
+    sl_left = slice(None, -2, None)
+    sl_right = slice(2, None, None)
     div_fac = 2.0
 
     dx = div_fac * data['dx'].flat[0]
 
-    px  = data["pressure"][sl_right,1:-1,1:-1]/dx
-    px -= data["pressure"][sl_left, 1:-1,1:-1]/dx
+    px = data["pressure"][sl_right, 1:-1, 1:-1]/dx
+    px -= data["pressure"][sl_left, 1:-1, 1:-1]/dx
 
     new_field = np.zeros(data["pressure"].shape, dtype='float64')
-    new_field[1:-1,1:-1,1:-1] = px
+    new_field[1:-1, 1:-1, 1:-1] = px
 
     return new_field
 
-def _Grad_Pressure_y(field, data) :
+
+def _Grad_Pressure_y(field, data):
 
     # We need to set up stencils
 
-    sl_left = slice(None,-2,None)
-    sl_right = slice(2,None,None)
+    sl_left = slice(None, -2, None)
+    sl_right = slice(2, None, None)
     div_fac = 2.0
 
     dy = div_fac * data['dy'].flat[0]
 
-    py  = data["pressure"][1:-1,sl_right,1:-1]/dy
-    py -= data["pressure"][1:-1,sl_left ,1:-1]/dy
+    py = data["pressure"][1:-1, sl_right, 1:-1]/dy
+    py -= data["pressure"][1:-1, sl_left, 1:-1]/dy
 
     new_field = np.zeros(data["pressure"].shape, dtype='float64')
-    new_field[1:-1,1:-1,1:-1] = py
+    new_field[1:-1, 1:-1, 1:-1] = py
 
     return new_field
 
-def _Grad_Pressure_z(field, data) :
+
+def _Grad_Pressure_z(field, data):
 
     # We need to set up stencils
 
-    sl_left = slice(None,-2,None)
-    sl_right = slice(2,None,None)
+    sl_left = slice(None, -2, None)
+    sl_right = slice(2, None, None)
     div_fac = 2.0
 
     dz = div_fac * data['dz'].flat[0]
 
-    pz  = data["pressure"][1:-1,1:-1,sl_right]/dz
-    pz -= data["pressure"][1:-1,1:-1,sl_left ]/dz
+    pz = data["pressure"][1:-1, 1:-1, sl_right]/dz
+    pz -= data["pressure"][1:-1, 1:-1, sl_left]/dz
 
     new_field = np.zeros(data["pressure"].shape, dtype='float64')
-    new_field[1:-1,1:-1,1:-1] = pz
+    new_field[1:-1, 1:-1, 1:-1] = pz
 
     return new_field
 
+
 # Define the "degree of hydrostatic equilibrium" field
 
-def _HSE(field, data) :
+
+def _HSE(field, data):
 
     gx = data["density"]*data["Grav_Accel_x"]
     gy = data["density"]*data["Grav_Accel_y"]
@@ -131,36 +144,37 @@
 
 # Now add the fields to the database
 
-add_field("Grav_Accel_x", function=_Grav_Accel_x, take_log=False,
-          validators=[ValidateSpatial(1,["Grav_Potential"])])
+yt.add_field("Grav_Accel_x", function=_Grav_Accel_x, take_log=False,
+             validators=[yt.ValidateSpatial(1, ["gravitational_potential"])])
 
-add_field("Grav_Accel_y", function=_Grav_Accel_y, take_log=False,
-          validators=[ValidateSpatial(1,["Grav_Potential"])])
+yt.add_field("Grav_Accel_y", function=_Grav_Accel_y, take_log=False,
+             validators=[yt.ValidateSpatial(1, ["gravitational_potential"])])
 
-add_field("Grav_Accel_z", function=_Grav_Accel_z, take_log=False,
-          validators=[ValidateSpatial(1,["Grav_Potential"])])
+yt.add_field("Grav_Accel_z", function=_Grav_Accel_z, take_log=False,
+             validators=[yt.ValidateSpatial(1, ["gravitational_potential"])])
 
-add_field("Grad_Pressure_x", function=_Grad_Pressure_x, take_log=False,
-          validators=[ValidateSpatial(1,["pressure"])])
+yt.add_field("Grad_Pressure_x", function=_Grad_Pressure_x, take_log=False,
+             validators=[yt.ValidateSpatial(1, ["pressure"])])
 
-add_field("Grad_Pressure_y", function=_Grad_Pressure_y, take_log=False,
-          validators=[ValidateSpatial(1,["pressure"])])
+yt.add_field("Grad_Pressure_y", function=_Grad_Pressure_y, take_log=False,
+             validators=[yt.ValidateSpatial(1, ["pressure"])])
 
-add_field("Grad_Pressure_z", function=_Grad_Pressure_z, take_log=False,
-          validators=[ValidateSpatial(1,["pressure"])])
+yt.add_field("Grad_Pressure_z", function=_Grad_Pressure_z, take_log=False,
+             validators=[yt.ValidateSpatial(1, ["pressure"])])
 
-add_field("HSE", function=_HSE, take_log=False)
+yt.add_field("HSE", function=_HSE, take_log=False)
 
-# Open two files, one at the beginning and the other at a later time when there's a
-# lot of sloshing going on.
+# Open two files, one at the beginning and the other at a later time when
+# there's a lot of sloshing going on.
 
-pfi = load("GasSloshingLowRes/sloshing_low_res_hdf5_plt_cnt_0000")
-pff = load("GasSloshingLowRes/sloshing_low_res_hdf5_plt_cnt_0350")
+dsi = yt.load("GasSloshingLowRes/sloshing_low_res_hdf5_plt_cnt_0000")
+dsf = yt.load("GasSloshingLowRes/sloshing_low_res_hdf5_plt_cnt_0350")
 
-# Sphere objects centered at the cluster potential minimum with a radius of 200 kpc
+# Sphere objects centered at the cluster potential minimum with a radius
+# of 200 kpc
 
-sphere_i = pfi.h.sphere(pfi.domain_center, (200, "kpc"))
-sphere_f = pff.h.sphere(pff.domain_center, (200, "kpc"))
+sphere_i = dsi.h.sphere(dsi.domain_center, (200, "kpc"))
+sphere_f = dsf.h.sphere(dsf.domain_center, (200, "kpc"))
 
 # Average "degree of hydrostatic equilibrium" in these spheres
 
@@ -170,10 +184,13 @@
 print "Degree of hydrostatic equilibrium initially: ", hse_i
 print "Degree of hydrostatic equilibrium later: ", hse_f
 
-# Just for good measure, take slices through the center of the domain of the two files
+# Just for good measure, take slices through the center of the domains
+# of the two files
 
-slc_i = SlicePlot(pfi, 2, ["density","HSE"], center=pfi.domain_center, width=(1.0, "mpc"))
-slc_f = SlicePlot(pff, 2, ["density","HSE"], center=pff.domain_center, width=(1.0, "mpc"))
+slc_i = yt.SlicePlot(dsi, 2, ["density", "HSE"], center=dsi.domain_center,
+                     width=(1.0, "mpc"))
+slc_f = yt.SlicePlot(dsf, 2, ["density", "HSE"], center=dsf.domain_center,
+                     width=(1.0, "mpc"))
 
 slc_i.save("initial")
 slc_f.save("final")

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/cookbook/zoomin_frames.py
--- a/doc/source/cookbook/zoomin_frames.py
+++ b/doc/source/cookbook/zoomin_frames.py
@@ -22,6 +22,6 @@
 for i,v in enumerate(np.logspace(
             0, np.log10(pf.index.get_smallest_dx()*min_dx), n_frames)):
     # We set our width as necessary for this frame ...
-    p.set_width(v, '1')
+    p.set_width(v, 'unitary')
     # ... and we save!
     p.save(frame_template % (i))

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/examining/loading_data.rst
--- a/doc/source/examining/loading_data.rst
+++ b/doc/source/examining/loading_data.rst
@@ -390,6 +390,11 @@
 
 These will be used set the units, if they are specified.
 
+Using yt to view and analyze Tipsy outputs from Gasoline
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+.. notebook:: tipsy_any_yt.ipynb
+
 .. _loading-artio-data:
 
 ARTIO Data

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/examining/tipsy_and_yt.ipynb
--- /dev/null
+++ b/doc/source/examining/tipsy_and_yt.ipynb
@@ -0,0 +1,195 @@
+{
+ "metadata": {
+  "name": "",
+  "signature": "sha256:a80c1b224c121c67e57acfa9183c5660a332a37556a492e230476b424827885f"
+ },
+ "nbformat": 3,
+ "nbformat_minor": 0,
+ "worksheets": [
+  {
+   "cells": [
+    {
+     "cell_type": "heading",
+     "level": 1,
+     "metadata": {},
+     "source": [
+      "Using yt to view and analyze Tipsy outputs from Gasoline"
+     ]
+    },
+    {
+     "cell_type": "heading",
+     "level": 2,
+     "metadata": {},
+     "source": [
+      "Loading Files"
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Alright, let's start with some basics.  Before we do anything, we will need to load a snapshot.  You can do this using the ```load``` convenience function.  yt will autodetect that you have a tipsy snapshot, and automatically set itself up appropriately."
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from yt.mods import *"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "We will be looking at a fairly low resolution dataset.  In the next cell, the `ds` object has an atribute called `n_ref` that tells the oct-tree how many particles to refine on.  The default is 64, but we'll get prettier plots (at the expense of a deeper tree) with 8.  Just passing the argument `n_ref=8` to load does this for us."
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      ">This dataset is available for download at http://yt-project.org/data/TipsyGalaxy.tar.gz (10 MB)."
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "ds = load('TipsyGalaxy/galaxy.00300', n_ref=8)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "We now have a `TipsyDataset` object called `ds`.  Let's see what fields it has."
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "ds.field_list"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "`yt` also defines so-called \"derived\" fields.  These fields are functions of the on-disk fields that live in the `field_list`.  There is a `derived_field_list` attribute attached to the `Dataset` object - let's take look at the derived fields in this dataset:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "ds.derived_field_list"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "All of the field in the `field_list` are arrays containing the values for the associated particles.  These haven't been smoothed or gridded in any way. We can grab the array-data for these particles using `ds.all_data()`. For example, let's take a look at a temperature-colored scatterplot of the gas particles in this output."
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "%matplotlib inline\n",
+      "import matplotlib.pyplot as plt"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "dd = ds.all_data()\n",
+      "xcoord = dd['Gas','Coordinates'][:,0].v\n",
+      "ycoord = dd['Gas','Coordinates'][:,1].v\n",
+      "logT = np.log10(dd['Gas','Temperature'])\n",
+      "plt.scatter(xcoord, ycoord, c=logT, s=2*logT, marker='o', edgecolor='none', vmin=2, vmax=6)\n",
+      "plt.xlim(-20,20)\n",
+      "plt.ylim(-20,20)\n",
+      "cb = plt.colorbar()\n",
+      "cb.set_label('$\\log_{10}$ Temperature')\n",
+      "plt.gcf().set_size_inches(15,10)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "heading",
+     "level": 2,
+     "metadata": {},
+     "source": [
+      "Making Smoothed Images"
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "`yt` will automatically generate smoothed versions of these fields that you can use to plot.  Let's make a temperature slice and a density projection."
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "SlicePlot(ds, 'z', ('gas','density'), width=(40, 'kpc'), center='m')"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "ProjectionPlot(ds, 'z', ('gas','density'), width=(40, 'kpc'), center='m')"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Not only are the values in the tipsy snapshot read and automatically smoothed, the auxiliary files that have physical significance are also smoothed.  Let's look at a slice of Iron mass fraction."
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "SlicePlot(ds, 'z', ('gas', 'FeMassFrac'), width=(40, 'kpc'), center='m')"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    }
+   ],
+   "metadata": {}
+  }
+ ]
+}
\ No newline at end of file

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 doc/source/reference/configuration.rst
--- a/doc/source/reference/configuration.rst
+++ b/doc/source/reference/configuration.rst
@@ -93,3 +93,5 @@
   uploading AMRSurface objects.
 * ``suppressStreamLogging`` (default: ``'False'``): If true, execution mode will be
   quiet.
+* ``stdoutStreamLogging`` (default: ``'False'``): If three, logging is directed
+  to stdout rather than stderr

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 setup.py
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,11 @@
     import distribute_setup
     distribute_setup.use_setuptools()
 
-from distutils.command.build_py import build_py
+try:
+   from distutils.command.build_py import build_py_2to3 \
+        as build_py
+except ImportError:
+    from distutils.command.build_py import build_py
 from numpy.distutils.misc_util import appendpath
 from numpy.distutils.command import install_data as np_install_data
 from numpy.distutils import log
@@ -100,11 +104,11 @@
     needs_cython = True
 
 if needs_cython:
-    print "Cython is a build-time requirement for the source tree of yt."
-    print "Please either install yt from a provided, release tarball,"
-    print "or install Cython (version 0.16 or higher)."
-    print "You may be able to accomplish this by typing:"
-    print "     pip install -U Cython"
+    print("Cython is a build-time requirement for the source tree of yt.")
+    print("Please either install yt from a provided, release tarball,")
+    print("or install Cython (version 0.16 or higher).")
+    print("You may be able to accomplish this by typing:")
+    print("     pip install -U Cython")
     sys.exit(1)
 
 ######
@@ -176,12 +180,12 @@
                                      shell=True)
 
     if (get_changeset.stderr.read() != ""):
-        print "Error in obtaining current changeset of the Mercurial repository"
+        print("Error in obtaining current changeset of the Mercurial repository")
         changeset = None
 
-    changeset = get_changeset.stdout.read().strip()
+    changeset = get_changeset.stdout.read().strip().decode("UTF-8")
     if (not re.search("^[0-9a-f]{12}", changeset)):
-        print "Current changeset of the Mercurial repository is malformed"
+        print("Current changeset of the Mercurial repository is malformed")
         changeset = None
 
     return changeset
@@ -215,7 +219,7 @@
             with open(os.path.join(target_dir, '__hg_version__.py'), 'w') as fobj:
                 fobj.write("hg_version = '%s'\n" % changeset)
 
-            build_py.run(self)
+        build_py.run(self)
 
 
 def configuration(parent_package='', top_path=None):

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 tests/runall.py
--- a/tests/runall.py
+++ b/tests/runall.py
@@ -87,7 +87,7 @@
             keys = set(registry_entries())
             tests_to_run += [t for t in new_tests if t in keys]
         tests = list(set(tests_to_run))
-        print "\n    ".join(tests)
+        print ("\n    ".join(tests))
         sys.exit(0)
 
     # Load the test pf and make sure it's good.

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/halo_finding/api.py
--- a/yt/analysis_modules/halo_finding/api.py
+++ b/yt/analysis_modules/halo_finding/api.py
@@ -13,7 +13,7 @@
 # The full license is in the file COPYING.txt, distributed with this software.
 #-----------------------------------------------------------------------------
 
-from halo_objects import \
+from .halo_objects import \
     Halo, \
     HOPHalo, \
     parallelHOPHalo, \

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/halo_finding/fof/EnzoFOF.c
--- a/yt/analysis_modules/halo_finding/fof/EnzoFOF.c
+++ b/yt/analysis_modules/halo_finding/fof/EnzoFOF.c
@@ -173,14 +173,37 @@
 __declspec(dllexport)
 #endif
 
-void initEnzoFOF(void)
+PyMODINIT_FUNC
+#if PY_MAJOR_VERSION >= 3
+#define _RETVAL m
+PyInit_EnzoFOF(void)
+#else
+#define _RETVAL 
+initEnzoFOF(void)
+#endif
 {
     PyObject *m, *d;
+#if PY_MAJOR_VERSION >= 3
+    static struct PyModuleDef moduledef = {
+        PyModuleDef_HEAD_INIT,
+        "EnzoFOF",           /* m_name */
+        "EnzoFOF Module",    /* m_doc */
+        -1,                  /* m_size */
+        _FOFMethods,          /* m_methods */
+        NULL,                /* m_reload */
+        NULL,                /* m_traverse */
+        NULL,                /* m_clear */
+        NULL,                /* m_free */
+    };
+    m = PyModule_Create(&moduledef); 
+#else
     m = Py_InitModule("EnzoFOF", _FOFMethods);
+#endif
     d = PyModule_GetDict(m);
     _FOFerror = PyErr_NewException("EnzoFOF.FOFerror", NULL, NULL);
     PyDict_SetItemString(d, "error", _FOFerror);
     import_array();
+    return _RETVAL;
 }
 
 /*

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/halo_finding/halo_objects.py
--- a/yt/analysis_modules/halo_finding/halo_objects.py
+++ b/yt/analysis_modules/halo_finding/halo_objects.py
@@ -24,6 +24,7 @@
 import os
 import os.path as path
 from collections import defaultdict
+from yt.extern.six import add_metaclass
 
 from yt.funcs import *
 
@@ -50,12 +51,13 @@
     ParallelAnalysisInterface, \
     parallel_blocking_call
 
+
+ at add_metaclass(ParallelDummy)
 class Halo(object):
     """
     A data source that returns particle information about the members of a
     HOP-identified halo.
     """
-    __metaclass__ = ParallelDummy  # This will proxy up our methods
     _distributed = False
     _processing = False
     _owner = 0
@@ -491,39 +493,39 @@
         # all the parameters except for the center of mass.
         com = self.center_of_mass()
         position = [self["particle_position_x"],
-		    self["particle_position_y"],
-		    self["particle_position_z"]]
+                    self["particle_position_y"],
+                    self["particle_position_z"]]
         # Locate the furthest particle from com, its vector length and index
-	DW = np.array([self.gridsize[0],self.gridsize[1],self.gridsize[2]])
-	position = [position[0] - com[0],
-		    position[1] - com[1],
-		    position[2] - com[2]]
-	# different cases of particles being on other side of boundary
-	for axis in range(np.size(DW)):
-	    cases = np.array([position[axis],
-	  		      position[axis] + DW[axis],
-			      position[axis] - DW[axis]])        
+        DW = np.array([self.gridsize[0],self.gridsize[1],self.gridsize[2]])
+        position = [position[0] - com[0],
+                    position[1] - com[1],
+                    position[2] - com[2]]
+        # different cases of particles being on other side of boundary
+        for axis in range(np.size(DW)):
+            cases = np.array([position[axis],
+                                position[axis] + DW[axis],
+                              position[axis] - DW[axis]])        
             # pick out the smallest absolute distance from com
             position[axis] = np.choose(np.abs(cases).argmin(axis=0), cases)
-	# find the furthest particle's index
-	r = np.sqrt(position[0]**2 +
-		    position[1]**2 +
-		    position[2]**2)
+        # find the furthest particle's index
+        r = np.sqrt(position[0]**2 +
+                    position[1]**2 +
+                    position[2]**2)
         A_index = r.argmax()
         mag_A = r.max()
         # designate the A vector
-	A_vector = (position[0][A_index],
-		    position[1][A_index],
-		    position[2][A_index])
+        A_vector = (position[0][A_index],
+                    position[1][A_index],
+                    position[2][A_index])
         # designate the e0 unit vector
         e0_vector = A_vector / mag_A
         # locate the tB particle position by finding the max B
-	e0_vector_copy = np.empty((np.size(position[0]), 3), dtype='float64')
+        e0_vector_copy = np.empty((np.size(position[0]), 3), dtype='float64')
         for i in range(3):
             e0_vector_copy[:, i] = e0_vector[i]
         rr = np.array([position[0],
-		       position[1],
-		       position[2]]).T # Similar to tB_vector in old code.
+                       position[1],
+                       position[2]]).T # Similar to tB_vector in old code.
         tC_vector = np.cross(e0_vector_copy, rr)
         te2 = tC_vector.copy()
         for dim in range(3):
@@ -954,7 +956,7 @@
         Examples
         --------
         >>> params = halos[0].get_ellipsoid_parameters()
-	"""
+        """
 
         basic_parameters = self._get_ellipsoid_parameters_basic_loadedhalo()
         toreturn = [self.center_of_mass()]

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/halo_finding/hop/EnzoHop.c
--- a/yt/analysis_modules/halo_finding/hop/EnzoHop.c
+++ b/yt/analysis_modules/halo_finding/hop/EnzoHop.c
@@ -23,6 +23,10 @@
 
 #include "numpy/ndarrayobject.h"
 
+#ifndef Py_TYPE
+    #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+
 void initgrouplist(Grouplist *g);
 void hop_main(KD kd, HC *my_comm, float densthres);
 void regroup_main(float dens_outer, HC *my_comm);
@@ -294,7 +298,7 @@
    Py_XDECREF(self->zpos);
    Py_XDECREF(self->mass);
 
-   self->ob_type->tp_free((PyObject*)self);
+   Py_TYPE(self)->tp_free((PyObject*)self);
 }
 
 static PyObject *
@@ -335,7 +339,7 @@
 
     int median = kdMedianJst(self->kd, d, l, u);
 
-    PyObject *omedian = PyInt_FromLong((long)median);
+    PyObject *omedian = PyLong_FromLong((long)median);
     return omedian;
 }
 
@@ -368,8 +372,8 @@
 
 static PyTypeObject
 kDTreeTypeDict = {
-   PyObject_HEAD_INIT(NULL)
-   0,                         /* ob_size */
+   PyVarObject_HEAD_INIT(NULL, 0)
+                            /* ob_size */
    "kDTree",               /* tp_name */
    sizeof(kDTreeType),         /* tp_basicsize */
    0,                         /* tp_itemsize */
@@ -409,10 +413,32 @@
    0,                         /* tp_new */
 };
 
-void initEnzoHop(void)
+PyMODINIT_FUNC
+#if PY_MAJOR_VERSION >= 3
+#define _RETVAL m
+PyInit_EnzoHop(void)
+#else
+#define _RETVAL 
+initEnzoHop(void)
+#endif
 {
     PyObject *m, *d;
+#if PY_MAJOR_VERSION >= 3
+    static struct PyModuleDef moduledef = {
+        PyModuleDef_HEAD_INIT,
+        "EnzoHop",           /* m_name */
+        "EnzoHop Module",    /* m_doc */
+        -1,                  /* m_size */
+        _HOPMethods,          /* m_methods */
+        NULL,                /* m_reload */
+        NULL,                /* m_traverse */
+        NULL,                /* m_clear */
+        NULL,                /* m_free */
+    };
+    m = PyModule_Create(&moduledef); 
+#else
     m = Py_InitModule("EnzoHop", _HOPMethods);
+#endif
     d = PyModule_GetDict(m);
     _HOPerror = PyErr_NewException("EnzoHop.HOPerror", NULL, NULL);
     PyDict_SetItemString(d, "error", _HOPerror);
@@ -426,6 +452,7 @@
    PyModule_AddObject(m, "kDTree", (PyObject*)&kDTreeTypeDict);
 
    import_array();
+   return _RETVAL;
 }
 
 /*

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/halo_finding/rockstar/rockstar_groupies.pyx
--- a/yt/analysis_modules/halo_finding/rockstar/rockstar_groupies.pyx
+++ b/yt/analysis_modules/halo_finding/rockstar/rockstar_groupies.pyx
@@ -6,8 +6,6 @@
 from libc.stdlib cimport malloc, free
 import sys
 
-
-
 # Importing relevant rockstar data types particle, fof halo, halo
 
 cdef import from "particle.h":
@@ -15,6 +13,10 @@
         np.int64_t id
         float pos[6]
 
+cdef import from "rockstar.h":
+    particle *global_particles "p"
+    void rockstar_cleanup()
+
 cdef import from "fof.h":
     struct fof:
         np.int64_t num_p
@@ -23,13 +25,34 @@
 cdef import from "halo.h":
     struct halo:
         np.int64_t id
-        float pos[6], corevel[3], bulkvel[3]
+        float pos[6]
+        float corevel[3]
+        float bulkvel[3]
         float m, r, child_r, vmax_r, mgrav,    vmax, rvmax, rs, klypin_rs, vrms
-        float J[3], energy, spin, alt_m[4], Xoff, Voff, b_to_a, c_to_a, A[3]
+        float J[3]
+        float energy, spin
+        float alt_m[4]
+        float Xoff, Voff, b_to_a, c_to_a
+        float A[3]
         float bullock_spin, kin_to_pot
         np.int64_t num_p, num_child_particles, p_start, desc, flags, n_core
         float min_pos_err, min_vel_err, min_bulkvel_err
 
+ctypedef packed struct haloflat:
+    np.int64_t id
+    float pos_x, pos_y, pos_z, pos_v, pos_u, pos_w
+    float corevel_x, corevel_y, corevel_z
+    float bulkvel_x, bulkvel_y, bulkvel_z
+    float m, r, child_r, vmax_r, mgrav,    vmax, rvmax, rs, klypin_rs, vrms
+    float J1, J2, J3
+    float energy, spin
+    float alt_m1, alt_m2, alt_m3, alt_m4
+    float Xoff, Voff, b_to_a, c_to_a
+    float A1, A2, A3
+    float bullock_spin, kin_to_pot
+    np.int64_t num_p, num_child_particles, p_start, desc, flags, n_core
+    float min_pos_err, min_vel_err, min_bulkvel_err
+
 # For finding sub halos import finder function and global variable
 # rockstar uses to store the results
 
@@ -38,6 +61,9 @@
     halo *halos
     np.int64_t num_halos
     void calc_mass_definition() nogil
+    void free_particle_copies() nogil
+    void alloc_particle_copies(np.int64_t total_copies) nogil
+    void free_halos() nogil
 
 # For outputing halos, rockstar style
 
@@ -48,6 +74,7 @@
 
 cdef import from "config.h":
     void setup_config() nogil
+    void output_config(char *fn) nogil
 
 cdef import from "config_vars.h":
     # Rockstar cleverly puts all of the config variables inside a templated
@@ -197,45 +224,87 @@
     def output_halos(self):
         output_halos(0, 0, 0, NULL) 
 
+    def return_halos(self):
+        cdef haloflat[:] haloview = <haloflat[:num_halos]> (<haloflat*> halos)
+        rv = np.asarray(haloview).copy()
+        rockstar_cleanup()
+        free_halos()
+        return rv
+
     @cython.boundscheck(False)
     @cython.wraparound(False)
-    def make_rockstar_fof(self, np.ndarray[np.int64_t, ndim=1] pid,
+    def make_rockstar_fof(self, np.ndarray[np.int64_t, ndim=1] pind,
+                                np.ndarray[np.int64_t, ndim=1] fof_tags,
                                 np.ndarray[np.float64_t, ndim=2] pos,
-                                np.ndarray[np.float64_t, ndim=2] vel,
-                                np.ndarray[np.int64_t, ndim=1] fof_tags,
-                                np.int64_t nfof,
-                                np.int64_t npart_max):
+                                np.ndarray[np.float64_t, ndim=2] vel):
 
         # Define fof object
 
         # Find number of particles
-        cdef np.int64_t i, j
-        cdef np.int64_t num_particles = pid.shape[0]
+        cdef np.int64_t i, j, k, ind, offset
+        cdef np.int64_t num_particles = pind.shape[0]
+        global global_particles
 
         # Allocate space for correct number of particles
-        cdef particle* particles = <particle*> malloc(npart_max * sizeof(particle))
         cdef fof fof_obj
-        fof_obj.particles = particles
 
-        cdef np.int64_t last_fof_tag = 1
-        cdef np.int64_t k = 0
-        for i in range(num_particles):
-            if fof_tags[i] < 0:
+        cdef np.int64_t max_count = 0
+        cdef np.int64_t next_tag, local_tag, last_fof_tag = -1
+        fof_obj.num_p = 0
+        j = 0
+        # We're going to do one iteration to get the most frequent value.
+        for i in range(pind.shape[0]):
+            ind = pind[i]
+            local_tag = fof_tags[ind]
+            # Don't count the null group
+            if local_tag == -1: continue
+            if local_tag != last_fof_tag:
+                if j > max_count:
+                    max_count = j
+                last_fof_tag = local_tag
+                j = 1
+            else:
+                j += 1
+        if j > max_count:
+            max_count = j
+        #print >> sys.stderr, "Most frequent occurrance: %s" % max_count
+        fof_obj.particles = <particle*> malloc(max_count * sizeof(particle))
+        j = 0
+        cdef int counter = 0, ndone = 0
+        cdef np.ndarray[np.int64_t, ndim=1] pcounts 
+        pcounts = np.zeros(np.unique(fof_tags).size, dtype="int64")
+        cdef np.int64_t frac = <np.int64_t> (pcounts.shape[0] / 20.0)
+        free_halos()
+        for i in range(pind.shape[0]):
+            ind = pind[i]
+            local_tag = fof_tags[ind]
+            # Skip this one -- it means no group.
+            if local_tag == -1:
                 continue
-            if fof_tags[i] != last_fof_tag:
-                last_fof_tag = fof_tags[i]
-                if k > 16:
-                    fof_obj.num_p = k
-                    find_subs(&fof_obj)
-                k = 0
-            particles[k].id = pid[i]
-
-            # fill in locations & velocities
-            for j in range(3):
-                particles[k].pos[j] = pos[i,j]
-                particles[k].pos[j+3] = vel[i,j]
-            k += 1
-        free(particles)
-
-
-
+            if i == pind.shape[0] - 1:
+                next_tag = local_tag + 1
+            else:
+                next_tag = fof_tags[pind[i+1]]
+            for k in range(3):
+                fof_obj.particles[j].pos[k] = pos[ind,k]
+                fof_obj.particles[j].pos[k+3] = vel[ind,k]
+            fof_obj.particles[j].id = j
+            fof_obj.num_p += 1
+            j += 1
+            # Now we check if we're the last one
+            if local_tag != next_tag:
+                pcounts[ndone] = fof_obj.num_p
+                counter += 1
+                ndone += 1
+                if counter == frac:
+                    print >> sys.stderr, "R*-ing % 5.1f%% done (%0.3f -> %0.3f)" % (
+                        (100.0 * ndone)/pcounts.size,
+                        fof_obj.particles[0].pos[2],
+                        halos[num_halos - 1].pos[2])
+                    counter = 0
+                global_particles = &fof_obj.particles[0]
+                find_subs(&fof_obj)
+                # Now we reset
+                fof_obj.num_p = j = 0
+        free(fof_obj.particles)
+        return pcounts

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/halo_finding/rockstar/rockstar_interface.pyx
--- a/yt/analysis_modules/halo_finding/rockstar/rockstar_interface.pyx
+++ b/yt/analysis_modules/halo_finding/rockstar/rockstar_interface.pyx
@@ -204,7 +204,7 @@
     p[0] = <particle *> malloc(sizeof(particle) * local_parts)
 
     conv[0] = conv[1] = conv[2] = pf.length_unit.in_units("Mpccm/h")
-    conv[3] = conv[4] = conv[5] = 1e-5
+    conv[3] = conv[4] = conv[5] = pf.velocity_unit.in_units("km/s")
     left_edge[0] = pf.domain_left_edge[0]
     left_edge[1] = pf.domain_left_edge[1]
     left_edge[2] = pf.domain_left_edge[2]

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/halo_finding/rockstar/setup.py
--- a/yt/analysis_modules/halo_finding/rockstar/setup.py
+++ b/yt/analysis_modules/halo_finding/rockstar/setup.py
@@ -12,15 +12,17 @@
     try:
         rd = open("rockstar.cfg").read().strip()
     except IOError:
-        print "Reading Rockstar location from rockstar.cfg failed."
-        print "Please place the base directory of your"
-        print "Rockstar install in rockstar.cfg and restart."
-        print "(ex: \"echo '/path/to/Rockstar-0.99' > rockstar.cfg\" )"
+        print("Reading Rockstar location from rockstar.cfg failed.")
+        print("Please place the base directory of your")
+        print("Rockstar install in rockstar.cfg and restart.")
+        print("(ex: \"echo '/path/to/Rockstar-0.99' > rockstar.cfg\" )")
         sys.exit(1)
     config.add_extension("rockstar_interface",
                          "yt/analysis_modules/halo_finding/rockstar/rockstar_interface.pyx",
                          library_dirs=[rd],
                          libraries=["rockstar"],
+                         #define_macros = [("THREADSAFE", "__thread")],
+                         define_macros = [("THREADSAFE", "")],
                          include_dirs=[rd,
                                        os.path.join(rd, "io"),
                                        os.path.join(rd, "util")])
@@ -28,6 +30,8 @@
                          "yt/analysis_modules/halo_finding/rockstar/rockstar_groupies.pyx",
                          library_dirs=[rd],
                          libraries=["rockstar"],
+                         #define_macros = [("THREADSAFE", "__thread")],
+                         define_macros = [("THREADSAFE", "")],
                          include_dirs=[rd,
                                        os.path.join(rd, "io"),
                                        os.path.join(rd, "util")])

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/spectral_integrator/spectral_frequency_integrator.py
--- a/yt/analysis_modules/spectral_integrator/spectral_frequency_integrator.py
+++ b/yt/analysis_modules/spectral_integrator/spectral_frequency_integrator.py
@@ -14,7 +14,6 @@
 # The full license is in the file COPYING.txt, distributed with this software.
 #-----------------------------------------------------------------------------
 
-from exceptions import IOError
 import h5py
 import numpy as np
 import os

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/analysis_modules/sunyaev_zeldovich/api.py
--- a/yt/analysis_modules/sunyaev_zeldovich/api.py
+++ b/yt/analysis_modules/sunyaev_zeldovich/api.py
@@ -9,4 +9,4 @@
 # The full license is in the file COPYING.txt, distributed with this software.
 #-----------------------------------------------------------------------------
 
-from projection import SZProjection
+from .projection import SZProjection

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -24,6 +24,7 @@
     logfile = 'False',
     coloredlogs = 'False',
     suppressstreamlogging = 'False',
+    stdoutStreamLogging = 'False',
     loglevel = '20',
     inline = 'False',
     numthreads = '-1',

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/data_objects/analyzer_objects.py
--- a/yt/data_objects/analyzer_objects.py
+++ b/yt/data_objects/analyzer_objects.py
@@ -16,16 +16,19 @@
 import inspect
 
 from yt.funcs import *
+from yt.extern.six import add_metaclass
 
 analysis_task_registry = {}
 
+class RegisteredTask(type):
+    def __init__(cls, name, b, d):
+        type.__init__(cls, name, b, d)
+        if hasattr(cls, "skip") and cls.skip == False:
+            return
+        analysis_task_registry[cls.__name__] = cls
+
+ at add_metaclass(RegisteredTask)
 class AnalysisTask(object):
-    class __metaclass__(type):
-        def __init__(cls, name, b, d):
-            type.__init__(cls, name, b, d)
-            if hasattr(cls, "skip") and cls.skip == False:
-                return
-            analysis_task_registry[cls.__name__] = cls
 
     def __init__(self, *args, **kwargs):
         # This should only get called if the subclassed object

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/data_objects/api.py
--- a/yt/data_objects/api.py
+++ b/yt/data_objects/api.py
@@ -13,20 +13,20 @@
 # The full license is in the file COPYING.txt, distributed with this software.
 #-----------------------------------------------------------------------------
 
-from grid_patch import \
+from .grid_patch import \
     AMRGridPatch
 
-from octree_subset import \
+from .octree_subset import \
     OctreeSubset
 
-from static_output import \
+from .static_output import \
     Dataset
 
-from particle_io import \
+from .particle_io import \
     ParticleIOHandler, \
     particle_handler_registry
 
-from profiles import \
+from .profiles import \
     YTEmptyProfileData, \
     BinnedProfile, \
     BinnedProfile1D, \
@@ -37,21 +37,21 @@
     Profile2D, \
     Profile3D
 
-from time_series import \
+from .time_series import \
     DatasetSeries, \
     DatasetSeriesObject
 
-from analyzer_objects import \
+from .analyzer_objects import \
     AnalysisTask, analysis_task
 
-from data_containers import \
+from .data_containers import \
     data_object_registry
 
-import construction_data_containers as __cdc
-import selection_data_containers as __sdc
+from . import construction_data_containers as __cdc
+from . import selection_data_containers as __sdc
 
-from image_array import \
+from .image_array import \
     ImageArray
 
-from particle_filters import \
+from .particle_filters import \
     particle_filter

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -17,10 +17,8 @@
 import numpy as np
 import math
 import weakref
-import exceptions
 import itertools
 import shelve
-from exceptions import ValueError, KeyError
 from functools import wraps
 import fileinput
 from re import finditer
@@ -181,8 +179,6 @@
         weight value before being integrated, and at the conclusion of the
         projection the resultant values will be divided by the projected
         `weight_field`.
-    max_level : int
-        If supplied, only cells at or below this level will be projected.
     center : array_like, optional
         The 'center' supplied to fields that use it.  Note that this does
         not have to have `coord` as one value.  Strictly optional.
@@ -210,7 +206,7 @@
     _con_args = ('axis', 'field', 'weight_field')
     _container_fields = ('px', 'py', 'pdx', 'pdy', 'weight_field')
     def __init__(self, field, axis, weight_field = None,
-                 center = None, pf = None, data_source=None, 
+                 center = None, pf = None, data_source = None,
                  style = "integrate", field_parameters = None):
         YTSelectionContainer2D.__init__(self, axis, pf, field_parameters)
         if style == "sum":
@@ -600,7 +596,7 @@
     ----------
     left_edge : array_like
         The left edge of the region to be extracted
-    rigth_edge : array_like
+    right_edge : array_like
         The left edge of the region to be extracted
     dims : array_like
         Number of cells along each axis of resulting grid.

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/data_objects/data_containers.py
--- a/yt/data_objects/data_containers.py
+++ b/yt/data_objects/data_containers.py
@@ -40,6 +40,7 @@
 from yt.fields.derived_field import \
     ValidateSpatial
 import yt.geometry.selection_routines
+from yt.extern.six import add_metaclass
 
 def force_array(item, shape):
     try:
@@ -71,7 +72,13 @@
     """
     pass
 
+class RegisteredDataContainer(type):
+    def __init__(cls, name, b, d):
+        type.__init__(cls, name, b, d)
+        if hasattr(cls, "_type_name") and not cls._skip_add:
+            data_object_registry[cls._type_name] = cls
 
+ at add_metaclass(RegisteredDataContainer)
 class YTDataContainer(object):
     """
     Generic YTDataContainer container.  By itself, will attempt to
@@ -86,12 +93,6 @@
     _field_cache = None
     _index = None
 
-    class __metaclass__(type):
-        def __init__(cls, name, b, d):
-            type.__init__(cls, name, b, d)
-            if hasattr(cls, "_type_name") and not cls._skip_add:
-                data_object_registry[cls._type_name] = cls
-
     def __init__(self, pf, field_parameters):
         """
         Typically this is never called directly, but only due to inheritance.
@@ -736,7 +737,7 @@
 
     def _get_pw(self, fields, center, width, origin, plot_type):
         axis = self.axis
-        self.fields = [k for k in self.field_data.keys()
+        self.fields = [k for k in self.field_data
                        if k not in self._key_fields]
         from yt.visualization.plot_window import \
             get_window_parameters, PWViewerMPL
@@ -812,12 +813,12 @@
             center = self.pf.arr(center, 'code_length')
         if iterable(width):
             w, u = width
-            width = self.pf.arr(w, input_units = u)
+            width = self.pf.quan(w, input_units = u)
         if height is None:
             height = width
         elif iterable(height):
             h, u = height
-            height = self.pf.arr(w, input_units = u)
+            height = self.pf.quan(w, input_units = u)
         if not iterable(resolution):
             resolution = (resolution, resolution)
         from yt.visualization.fixed_resolution import FixedResolutionBuffer

diff -r 3fb307c4736d3c20ba94c3042f48699e6a49d322 -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 yt/data_objects/grid_patch.py
--- a/yt/data_objects/grid_patch.py
+++ b/yt/data_objects/grid_patch.py
@@ -13,7 +13,6 @@
 # The full license is in the file COPYING.txt, distributed with this software.
 #-----------------------------------------------------------------------------
 
-import exceptions
 import pdb
 import weakref
 import itertools

This diff is so big that we needed to truncate the remainder.

https://bitbucket.org/yt_analysis/yt/commits/124b4898f29d/
Changeset:   124b4898f29d
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-07 06:07:16
Summary:     A small change to allow ParticleTrajectories to accept an already existing DatasetSeries object instead of creating one from scratch
Affected #:  1 file

diff -r c91dfb4837a8d4cc5f90e261305804f54ef4f318 -r 124b4898f29d2867bfac8193e2a4c609c8e919b9 yt/analysis_modules/particle_trajectories/particle_trajectories.py
--- a/yt/analysis_modules/particle_trajectories/particle_trajectories.py
+++ b/yt/analysis_modules/particle_trajectories/particle_trajectories.py
@@ -32,9 +32,9 @@
     
     Parameters
     ----------
-    filenames : list of strings
-        A time-sorted list of filenames to construct the DatasetSeries
-        object.
+    outputs : `yt.data_objects.time_series.DatasetSeries` or list of strings
+        DatasetSeries object, or a time-sorted list of filenames to
+        construct a new DatasetSeries object.
     indices : array_like
         An integer array of particle indices whose trajectories we
         want to track. If they are not sorted they will be sorted.
@@ -59,11 +59,14 @@
     >>> for t in trajs :
     >>>     print t["particle_velocity_x"].max(), t["particle_velocity_x"].min()
     """
-    def __init__(self, filenames, indices, fields=None) :
+    def __init__(self, outputs, indices, fields=None) :
 
         indices.sort() # Just in case the caller wasn't careful
         self.field_data = YTFieldData()
-        self.data_series = DatasetSeries.from_filenames(filenames)
+        if isinstance(outputs, DatasetSeries):
+            self.data_series = outputs
+        else:
+            self.data_series = DatasetSeries.from_filenames(outputs)
         self.masks = []
         self.sorts = []
         self.array_indices = []


https://bitbucket.org/yt_analysis/yt/commits/f0ad4b36d641/
Changeset:   f0ad4b36d641
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-07 15:33:36
Summary:     Getting rid of kwargs where we don't need it, making _sum_only protected
Affected #:  2 files

diff -r 124b4898f29d2867bfac8193e2a4c609c8e919b9 -r f0ad4b36d6418a1999708bf3250c5fed1640745f yt/data_objects/construction_data_containers.py
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -211,10 +211,10 @@
         YTSelectionContainer2D.__init__(self, axis, pf, field_parameters)
         if style == "sum":
             self.proj_style = "integrate"
-            self.sum_only = True
+            self._sum_only = True
         else:
             self.proj_style = style
-            self.sum_only = False
+            self._sum_only = False
         if style == "mip":
             self.func = np.max
         elif style == "integrate" or style == "sum":
@@ -351,7 +351,7 @@
         tree.initialize_chunk(i1, i2, ilevel)
 
     def _handle_chunk(self, chunk, fields, tree):
-        if self.proj_style == "mip" or self.sum_only:
+        if self.proj_style == "mip" or self._sum_only:
             dl = 1.0
         else:
             # This gets explicitly converted to cm

diff -r 124b4898f29d2867bfac8193e2a4c609c8e919b9 -r f0ad4b36d6418a1999708bf3250c5fed1640745f yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -752,6 +752,9 @@
             else:
                 (unit_x, unit_y) = self._axes_unit_names
 
+            # For some plots we may set aspect by hand, such as for PPV data.
+            # This will likely be replaced at some point by the coordinate handler
+            # setting plot aspect.
             if self.aspect is None:
                 self.aspect = np.float64(self.pf.quan(1.0, unit_y)/(self.pf.quan(1.0, unit_x)))
 
@@ -1019,7 +1022,8 @@
     _frb_generator = FixedResolutionBuffer
 
     def __init__(self, pf, axis, fields, center='c', width=None, axes_unit=None,
-                 origin='center-window', fontsize=18, field_parameters=None, **kwargs):
+                 origin='center-window', fontsize=18, field_parameters=None,
+                 window_size=8.0, aspect=None):
         # this will handle time series data and controllers
         ts = self._initialize_dataset(pf)
         self.ts = ts
@@ -1031,7 +1035,8 @@
             field_parameters = field_parameters, center=center)
         slc.get_data(fields)
         PWViewerMPL.__init__(self, slc, bounds, origin=origin,
-                             fontsize=fontsize, fields=fields, **kwargs)
+                             fontsize=fontsize, fields=fields,
+                             window_size=window_size, aspect=aspect)
         if axes_unit is None:
             axes_unit = get_axes_unit(width, pf)
         self.set_axes_unit(axes_unit)
@@ -1146,7 +1151,7 @@
     def __init__(self, pf, axis, fields, center='c', width=None, axes_unit=None,
                  weight_field=None, max_level=None, origin='center-window',
                  fontsize=18, field_parameters=None, data_source=None,
-                 proj_style = "integrate", **kwargs):
+                 proj_style = "integrate", window_size=8.0, aspect=None):
         ts = self._initialize_dataset(pf)
         self.ts = ts
         pf = self.pf = ts[0]
@@ -1157,7 +1162,7 @@
                          center=center, data_source=data_source,
                          field_parameters = field_parameters, style = proj_style)
         PWViewerMPL.__init__(self, proj, bounds, fields=fields, origin=origin,
-                             fontsize=fontsize, **kwargs)
+                             fontsize=fontsize, window_size=window_size, aspect=aspect)
         if axes_unit is None:
             axes_unit = get_axes_unit(width, pf)
         self.set_axes_unit(axes_unit)


https://bitbucket.org/yt_analysis/yt/commits/22d5d89b1887/
Changeset:   22d5d89b1887
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-07 18:06:45
Summary:     Merge
Affected #:  4 files

diff -r f0ad4b36d6418a1999708bf3250c5fed1640745f -r 22d5d89b1887478169a0a09905749bd46502764e doc/source/analyzing/analysis_modules/halo_catalogs.rst
--- a/doc/source/analyzing/analysis_modules/halo_catalogs.rst
+++ b/doc/source/analyzing/analysis_modules/halo_catalogs.rst
@@ -15,11 +15,12 @@
 details on the relative differences between these halo finders see 
 :ref:`halo_finding`.
 
-.. code-block:: 
-    from yt.mods import *
-    from yt.analysis_modules.halo_analysis.api import HaloCatalog
-    data_pf = load('Enzo_64/RD0006/RedshiftOutput0006')
-    hc = HaloCatalog(data_pf=data_pf, finder_method='hop')
+.. code-block:: python
+
+   from yt.mods import *
+   from yt.analysis_modules.halo_analysis.api import HaloCatalog
+   data_pf = load('Enzo_64/RD0006/RedshiftOutput0006')
+   hc = HaloCatalog(data_pf=data_pf, finder_method='hop')
 
 A halo catalog may also be created from already run rockstar outputs. 
 This method is not implemented for previously run friends-of-friends or 
@@ -28,9 +29,10 @@
 only specify the file output by the processor with ID 0. Note that the 
 argument for supplying a rockstar output is `halos_pf`, not `data_pf`.
 
-.. code-block:: 
-    halos_pf = load(path+'rockstar_halos/halos_0.0.bin')
-    hc = HaloCatalog(halos_pf=halos_pf)
+.. code-block:: python
+
+   halos_pf = load(path+'rockstar_halos/halos_0.0.bin')
+   hc = HaloCatalog(halos_pf=halos_pf)
 
 Although supplying only the binary output of the rockstar halo finder 
 is sufficient for creating a halo catalog, it is not possible to find 
@@ -38,10 +40,11 @@
 with the dataset from which they were found, supply arguments to both 
 halos_pf and data_pf.
 
-.. code-block::
-    halos_pf = load(path+'rockstar_halos/halos_0.0.bin')
-    data_pf = load('Enzo_64/RD0006/RedshiftOutput0006')
-    hc = HaloCatalog(data_pf=data_pf, halos_pf=halos_pf)
+.. code-block:: python
+
+   halos_pf = load(path+'rockstar_halos/halos_0.0.bin')
+   data_pf = load('Enzo_64/RD0006/RedshiftOutput0006')
+   hc = HaloCatalog(data_pf=data_pf, halos_pf=halos_pf)
 
 A data container can also be supplied via keyword data_source, 
 associated with either dataset, to control the spatial region in 
@@ -72,9 +75,9 @@
 
 An example of adding a filter:
 
-.. code-block::
+.. code-block:: python
 
-    hc.add_filter('quantity_value', 'particle_mass', '>', 1E13, 'Msun')
+   hc.add_filter('quantity_value', 'particle_mass', '>', 1E13, 'Msun')
 
 Currently quantity_value is the only available filter, but more can be 
 added by the user by defining a function that accepts a halo object as 
@@ -85,20 +88,21 @@
 
 An example of defining your own filter:
 
-.. code-block::
-    def my_filter_function(halo):
-        
-        # Define condition for filter
-        filter_value = True
-        
-        # Return a boolean value 
-        return filter_value
+.. code-block:: python
 
-    # Add your filter to the filter registry
-    add_filter("my_filter", my_filter_function)
+   def my_filter_function(halo):
+       
+       # Define condition for filter
+       filter_value = True
+       
+       # Return a boolean value 
+       return filter_value
 
-    # ... Later on in your script
-    hc.add_filter("my_filter")
+   # Add your filter to the filter registry
+   add_filter("my_filter", my_filter_function)
+
+   # ... Later on in your script
+   hc.add_filter("my_filter")
 
 Quantities
 ----------
@@ -118,25 +122,26 @@
 
 An example of adding a quantity:
 
-.. code-block::
-    hc.add_quantity('center_of_mass')
+.. code-block:: python
+
+   hc.add_quantity('center_of_mass')
 
 An example of defining your own quantity:
 
-.. code-block::
+.. code-block:: python
 
-    def my_quantity_function(halo):
-        # Define quantity to return
-        quantity = 5
-        
-        return quantity
+   def my_quantity_function(halo):
+       # Define quantity to return
+       quantity = 5
+       
+       return quantity
 
-    # Add your filter to the filter registry
-    add_quantity('my_quantity', my_quantity_function)
+   # Add your filter to the filter registry
+   add_quantity('my_quantity', my_quantity_function)
 
 
-    # ... Later on in your script
-    hc.add_quantity("my_quantity") 
+   # ... Later on in your script
+   hc.add_quantity("my_quantity") 
 
 Callbacks
 ---------
@@ -150,8 +155,9 @@
 An example of using a pre-defined callback where we create a sphere for 
 each halo with a radius that is twice the saved “radius”.
 
-.. code-block::
-    hc.add_callback("sphere", factor=2.0)
+.. code-block:: python
+
+   hc.add_callback("sphere", factor=2.0)
     
 Currently available callbacks are located in 
 yt/analysis_modules/halo_analysis/halo_callbacks.py. New callbacks may 
@@ -161,19 +167,19 @@
 
 An example of defining your own callback:
 
-.. code-block::
+.. code-block:: python
 
-    def my_callback_function(halo):
-        # Perform some callback actions here
-        x = 2
-        halo.x_val = x
+   def my_callback_function(halo):
+       # Perform some callback actions here
+       x = 2
+       halo.x_val = x
 
-    # Add the callback to the callback registry
-    add_callback('my_callback', my_callback_function)
+   # Add the callback to the callback registry
+   add_callback('my_callback', my_callback_function)
 
 
-    # ...  Later on in your script
-    hc.add_callback("my_callback")
+   # ...  Later on in your script
+   hc.add_callback("my_callback")
 
 Running Analysis
 ================
@@ -181,8 +187,9 @@
 After all callbacks, quantities, and filters have been added, the 
 analysis begins with a call to HaloCatalog.create.
 
-.. code-block::
-    hc.create()
+.. code-block:: python
+
+   hc.create()
 
 The save_halos keyword determines whether the actual Halo objects 
 are saved after analysis on them has completed or whether just the 
@@ -206,13 +213,14 @@
 standard call to load. Any side data, such as profiles, can be reloaded 
 with a load_profiles callback and a call to HaloCatalog.load.
 
-.. code-block::
-    hpf = load(path+"halo_catalogs/catalog_0046/catalog_0046.0.h5")
-    hc = HaloCatalog(halos_pf=hpf,
-                     output_dir="halo_catalogs/catalog_0046")
-    hc.add_callback("load_profiles", output_dir="profiles",
-                    filename="virial_profiles")
-    hc.load()
+.. code-block:: python
+
+   hpf = load(path+"halo_catalogs/catalog_0046/catalog_0046.0.h5")
+   hc = HaloCatalog(halos_pf=hpf,
+                    output_dir="halo_catalogs/catalog_0046")
+   hc.add_callback("load_profiles", output_dir="profiles",
+                   filename="virial_profiles")
+   hc.load()
 
 Summary
 =======

diff -r f0ad4b36d6418a1999708bf3250c5fed1640745f -r 22d5d89b1887478169a0a09905749bd46502764e doc/source/examining/loading_data.rst
--- a/doc/source/examining/loading_data.rst
+++ b/doc/source/examining/loading_data.rst
@@ -282,7 +282,7 @@
 
 .. code-block:: python
 
-    ( "Gas", "Halo", "Disk", "Bulge", "Stars", "Bndry" )
+   ( "Gas", "Halo", "Disk", "Bulge", "Stars", "Bndry" )
 
 You can specify alternate names, but note that this may cause problems with the
 field specification if none of the names match old names.
@@ -300,23 +300,23 @@
 
 .. code-block:: python
    
-    default      = (('Npart', 6, 'i'),
-                    ('Massarr', 6, 'd'),
-                    ('Time', 1, 'd'),
-                    ('Redshift', 1, 'd'),
-                    ('FlagSfr', 1, 'i'),
-                    ('FlagFeedback', 1, 'i'),
-                    ('Nall', 6, 'i'),
-                    ('FlagCooling', 1, 'i'),
-                    ('NumFiles', 1, 'i'),
-                    ('BoxSize', 1, 'd'),
-                    ('Omega0', 1, 'd'),
-                    ('OmegaLambda', 1, 'd'),
-                    ('HubbleParam', 1, 'd'),
-                    ('FlagAge', 1, 'i'),
-                    ('FlagMEtals', 1, 'i'),
-                    ('NallHW', 6, 'i'),
-                    ('unused', 16, 'i'))
+   default      = (('Npart', 6, 'i'),
+                   ('Massarr', 6, 'd'),
+                   ('Time', 1, 'd'),
+                   ('Redshift', 1, 'd'),
+                   ('FlagSfr', 1, 'i'),
+                   ('FlagFeedback', 1, 'i'),
+                   ('Nall', 6, 'i'),
+                   ('FlagCooling', 1, 'i'),
+                   ('NumFiles', 1, 'i'),
+                   ('BoxSize', 1, 'd'),
+                   ('Omega0', 1, 'd'),
+                   ('OmegaLambda', 1, 'd'),
+                   ('HubbleParam', 1, 'd'),
+                   ('FlagAge', 1, 'i'),
+                   ('FlagMEtals', 1, 'i'),
+                   ('NallHW', 6, 'i'),
+                   ('unused', 16, 'i'))
 
 These items will all be accessible inside the object ``pf.parameters``, which
 is a dictionary.  You can add combinations of new items, specified in the same
@@ -371,7 +371,7 @@
 
 .. code-block:: python
 
-    ds = load("./halo1e11_run1.00400")
+   ds = load("./halo1e11_run1.00400")
 
 .. _specifying-cosmology-tipsy:
 
@@ -393,7 +393,7 @@
 Using yt to view and analyze Tipsy outputs from Gasoline
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
-.. notebook:: tipsy_any_yt.ipynb
+.. notebook:: tipsy_and_yt.ipynb
 
 .. _loading-artio-data:
 
@@ -414,7 +414,7 @@
 
 .. code-block:: python
 
-    ds = load("./A11QR1/s11Qzm1h2_a1.0000.art")
+   ds = load("./A11QR1/s11Qzm1h2_a1.0000.art")
 
 .. _loading-art-data:
 
@@ -551,29 +551,29 @@
   installations of this package and the `PyWCS <http://stsdas.stsci
   .edu/astrolib/pywcs/>`_ package are not supported.
 
-Though FITS a image is composed of one data cube in the FITS file,
+Though a FITS image is composed of a single array in the FITS file,
 upon being loaded into yt it is automatically decomposed into grids:
 
 .. code-block:: python
 
-  from yt.mods import *
-  ds = load("m33_hi.fits")
-  ds.print_stats()
+   from yt.mods import *
+   ds = load("m33_hi.fits")
+   ds.print_stats()
 
 .. parsed-literal::
 
-  level	  # grids     # cells     # cells^3
-  ------------------------------------------
-    0	     512     981940800	     994
-  ------------------------------------------
-             512     981940800
+   level  # grids         # cells     # cells^3
+   ----------------------------------------------
+     0	     512	  981940800       994
+   ----------------------------------------------
+             512	  981940800
 
 yt will generate its own domain decomposition, but the number of grids can be
 set manually by passing the ``nprocs`` parameter to the ``load`` call:
 
 .. code-block:: python
 
-  ds = load("m33_hi.fits", nprocs=1024)
+   ds = load("m33_hi.fits", nprocs=1024)
 
 Making the Most of `yt` for FITS Data
 +++++++++++++++++++++++++++++++++++++
@@ -596,12 +596,12 @@
 
 .. code-block:: python
 
-    import astropy.io.fits as pyfits
-    f = pyfits.open("xray_flux_image.fits", mode="update")
-    f[0].header["BUNIT"] = "cts/s/pixel"
-    f[0].header["BTYPE"] = "flux"
-    f.flush()
-    f.close()
+   import astropy.io.fits as pyfits
+   f = pyfits.open("xray_flux_image.fits", mode="update")
+   f[0].header["BUNIT"] = "cts/s/pixel"
+   f[0].header["BTYPE"] = "flux"
+   f.flush()
+   f.close()
 
 FITS Coordinates
 ++++++++++++++++
@@ -651,7 +651,7 @@
 
 .. code-block:: python
 
-    ds = load("flux.fits", auxiliary_files=["temp.fits","metal.fits"])
+   ds = load("flux.fits", auxiliary_files=["temp.fits","metal.fits"])
 
 The image blocks in each of these files will be loaded as a separate field,
 provided they have the same dimensions as the image blocks in the main file.
@@ -683,11 +683,11 @@
 
 .. code-block:: python
 
-  # passing a single float
-  ds = load("m33_hi.fits", nan_mask=0.0)
+   # passing a single float
+   ds = load("m33_hi.fits", nan_mask=0.0)
 
-  # passing a dict
-  ds = load("m33_hi.fits", nan_mask={"intensity":-1.0,"temperature":0.0})
+   # passing a dict
+   ds = load("m33_hi.fits", nan_mask={"intensity":-1.0,"temperature":0.0})
 
 Generally, AstroPy may generate a lot of warnings about individual FITS
 files, many of which you may want to ignore. If you want to see these
@@ -856,9 +856,9 @@
 
 .. code-block:: python
 
-    for g in grid_data:
-        g["number_of_particles"] = 100000
-        g["particle_position_x"] = np.random.random((g["number_of_particles"]))
+   for g in grid_data:
+       g["number_of_particles"] = 100000
+       g["particle_position_x"] = np.random.random((g["number_of_particles"]))
 
 .. rubric:: Caveats
 

diff -r f0ad4b36d6418a1999708bf3250c5fed1640745f -r 22d5d89b1887478169a0a09905749bd46502764e doc/source/reference/api/api.rst
--- a/doc/source/reference/api/api.rst
+++ b/doc/source/reference/api/api.rst
@@ -200,10 +200,10 @@
 .. autosummary::
    :toctree: generated/
 
-   ~yt.frontends.halo_catalogs.data_structures.RockstarBinaryFile
-   ~yt.frontends.halo_catalogs.data_structures.RockstarDataset
-   ~yt.frontends.halo_catalogs.fields.RockstarFieldInfo
-   ~yt.frontends.halo_catalogs.io.IOHandlerRockstarBinary
+   ~yt.frontends.halo_catalogs.rockstar.data_structures.RockstarBinaryFile
+   ~yt.frontends.halo_catalogs.rockstar.data_structures.RockstarDataset
+   ~yt.frontends.halo_catalogs.rockstar.fields.RockstarFieldInfo
+   ~yt.frontends.halo_catalogs.rockstar.io.IOHandlerRockstarBinary
 
 MOAB
 ^^^^
@@ -313,7 +313,7 @@
    ~yt.analysis_modules.halo_finding.halo_objects.FOFHaloFinder
    ~yt.analysis_modules.halo_finding.halo_objects.HOPHaloFinder
    ~yt.analysis_modules.halo_finding.halo_objects.parallelHF
-   ~yt.analysis_modules.halo_finding.rockstar.api.RockstarHaloFinder
+   ~yt.analysis_modules.halo_finding.rockstar.rockstar.RockstarHaloFinder
 
 You can also operate on the Halo and HAloList objects themselves:
 
@@ -616,11 +616,8 @@
    ~yt.visualization.plot_modifications.ArrowCallback
    ~yt.visualization.plot_modifications.ClumpContourCallback
    ~yt.visualization.plot_modifications.ContourCallback
-   ~yt.visualization.plot_modifications.CoordAxesCallback
    ~yt.visualization.plot_modifications.CuttingQuiverCallback
    ~yt.visualization.plot_modifications.GridBoundaryCallback
-   ~yt.visualization.plot_modifications.HopCircleCallback
-   ~yt.visualization.plot_modifications.HopParticleCallback
    ~yt.visualization.plot_modifications.LabelCallback
    ~yt.visualization.plot_modifications.LinePlotCallback
    ~yt.visualization.plot_modifications.MarkerAnnotateCallback
@@ -630,7 +627,6 @@
    ~yt.visualization.plot_modifications.SphereCallback
    ~yt.visualization.plot_modifications.TextLabelCallback
    ~yt.visualization.plot_modifications.TitleCallback
-   ~yt.visualization.plot_modifications.UnitBoundaryCallback
    ~yt.visualization.plot_modifications.VelocityCallback
 
 Function List


https://bitbucket.org/yt_analysis/yt/commits/721b37f6b437/
Changeset:   721b37f6b437
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-08 23:42:15
Summary:     Merge
Affected #:  7 files

diff -r 22d5d89b1887478169a0a09905749bd46502764e -r 721b37f6b4378a5487d0208dfd0897eace5db5a1 yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -32,6 +32,9 @@
 from yt.utilities.lib.geometry_utils import compute_morton
 from yt.geometry.particle_oct_container import \
     ParticleOctreeContainer
+from yt.units.yt_array import YTArray
+from yt.units.dimensions import length
+from yt.utilities.exceptions import YTInvalidPositionArray
 
 def cell_count_cache(func):
     def cc_cache_func(self, dobj):
@@ -333,3 +336,34 @@
     @property
     def dds(self):
         return self._fwidth[0,0,0,self.ind,:]
+
+class YTPositionArray(YTArray):
+    @property
+    def morton(self):
+        self.validate()
+        eps = np.finfo(self.dtype).eps
+        LE = self.min(axis=0) - eps * self.uq
+        RE = self.max(axis=0) + eps * self.uq
+        morton = compute_morton(
+            self[:,0], self[:,1], self[:,2],
+            LE, RE)
+        return morton
+
+    def to_octree(self, over_refine_factor = 1, dims = (1,1,1),
+                  n_ref = 64):
+        mi = self.morton
+        mi.sort()
+        eps = np.finfo(self.dtype).eps
+        LE = self.min(axis=0) - eps * self.uq
+        RE = self.max(axis=0) + eps * self.uq
+        octree = ParticleOctreeContainer(dims, LE, RE, 
+            over_refine = over_refine_factor)
+        octree.n_ref = n_ref
+        octree.add(mi)
+        octree.finalize()
+        return octree
+
+    def validate(self):
+        if len(self.shape) != 2 or self.shape[1] != 3 \
+           or self.units.dimensions != length:
+            raise YTInvalidPositionArray(self.shape, self.units.dimensions)

diff -r 22d5d89b1887478169a0a09905749bd46502764e -r 721b37f6b4378a5487d0208dfd0897eace5db5a1 yt/data_objects/profiles.py
--- a/yt/data_objects/profiles.py
+++ b/yt/data_objects/profiles.py
@@ -853,7 +853,10 @@
         if fname is None:
             raise KeyError(field)
         else:
-            return self.field_data[fname].in_units(self.field_units[fname])
+            if getattr(self, 'fractional', False):
+                return self.field_data[fname]
+            else:
+                return self.field_data[fname].in_units(self.field_units[fname])
 
     def items(self):
         return [(k,self[k]) for k in self.field_data.keys()]

diff -r 22d5d89b1887478169a0a09905749bd46502764e -r 721b37f6b4378a5487d0208dfd0897eace5db5a1 yt/data_objects/tests/test_ortho_rays.py
--- a/yt/data_objects/tests/test_ortho_rays.py
+++ b/yt/data_objects/tests/test_ortho_rays.py
@@ -11,8 +11,7 @@
 
         my_oray = pf.ortho_ray(ax, ocoord)
 
-        my_axes = range(3)
-        del my_axes[ax]
+        my_axes = pf.coordinates.x_axis[ax], pf.coordinates.y_axis[ax]
 
         # find the cells intersected by the ortho ray
         my_all = pf.h.all_data()

diff -r 22d5d89b1887478169a0a09905749bd46502764e -r 721b37f6b4378a5487d0208dfd0897eace5db5a1 yt/geometry/cartesian_coordinates.py
--- a/yt/geometry/cartesian_coordinates.py
+++ b/yt/geometry/cartesian_coordinates.py
@@ -110,11 +110,11 @@
     axis_id = { 'x' : 0, 'y' : 1, 'z' : 2,
                  0  : 0,  1  : 1,  2  : 2}
 
-    x_axis = { 'x' : 1, 'y' : 0, 'z' : 0,
-                0  : 1,  1  : 0,  2  : 0}
+    x_axis = { 'x' : 1, 'y' : 2, 'z' : 0,
+                0  : 1,  1  : 2,  2  : 0}
 
-    y_axis = { 'x' : 2, 'y' : 2, 'z' : 1,
-                0  : 2,  1  : 2,  2  : 1}
+    y_axis = { 'x' : 2, 'y' : 0, 'z' : 1,
+                0  : 2,  1  : 0,  2  : 1}
 
     @property
     def period(self):

diff -r 22d5d89b1887478169a0a09905749bd46502764e -r 721b37f6b4378a5487d0208dfd0897eace5db5a1 yt/geometry/ppv_coordinates.py
--- a/yt/geometry/ppv_coordinates.py
+++ b/yt/geometry/ppv_coordinates.py
@@ -46,19 +46,23 @@
                 self.x_axis[axis] = 1
                 self.x_axis[lower_ax] = 1
                 self.x_axis[axis_name] = 1
-            else:
+                self.y_axis[axis] = 2
+                self.y_axis[lower_ax] = 2
+                self.y_axis[axis_name] = 2
+            elif axis == 1:
+                self.x_axis[axis] = 2
+                self.x_axis[lower_ax] = 2
+                self.x_axis[axis_name] = 2
+                self.y_axis[axis] = 0
+                self.y_axis[lower_ax] = 0
+                self.y_axis[axis_name] = 0
+            elif axis == 2:
                 self.x_axis[axis] = 0
                 self.x_axis[lower_ax] = 0
                 self.x_axis[axis_name] = 0
-
-            if axis == 2:
                 self.y_axis[axis] = 1
                 self.y_axis[lower_ax] = 1
                 self.y_axis[axis_name] = 1
-            else:
-                self.y_axis[axis] = 2
-                self.y_axis[lower_ax] = 2
-                self.y_axis[axis_name] = 2
 
         self.default_unit_label = {}
         self.default_unit_label[pf.lon_axis] = "pixel"
@@ -70,3 +74,4 @@
 
     def convert_from_cylindrical(self, coord):
         raise NotImplementedError
+

diff -r 22d5d89b1887478169a0a09905749bd46502764e -r 721b37f6b4378a5487d0208dfd0897eace5db5a1 yt/utilities/exceptions.py
--- a/yt/utilities/exceptions.py
+++ b/yt/utilities/exceptions.py
@@ -367,3 +367,13 @@
                But being asked to add it with:
                %s""" % (self.field, self.old_spec, self.new_spec)
         return r
+
+class YTInvalidPositionArray(Exception):
+    def __init__(self, shape, dimensions):
+        self.shape = shape
+        self.dimensions = dimensions
+
+    def __str__(self):
+        r = """Position arrays must be length and shape (N,3).
+               But this one has %s and %s.""" % (self.dimensions, self.shape)
+        return r

diff -r 22d5d89b1887478169a0a09905749bd46502764e -r 721b37f6b4378a5487d0208dfd0897eace5db5a1 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -473,7 +473,7 @@
         scales = {True: 'log', False: 'linear'}
         return scales[x_log], scales[y_log]
 
-    def _get_field_label(self, field, field_info, field_unit):
+    def _get_field_label(self, field, field_info, field_unit, fractional=False):
         field_unit = field_unit.latex_representation()
         field_name = field_info.display_name
         if isinstance(field, tuple): field = field[1]
@@ -483,7 +483,9 @@
         elif field_name.find('$') == -1:
             field_name = field_name.replace(' ','\/')
             field_name = r'$\rm{'+field_name+r'}$'
-        if field_unit is None or field_unit == '':
+        if fractional:
+            label = field_name + r'$\rm{\/Probability\/Density}$'
+        elif field_unit is None or field_unit == '':
             label = field_name
         else:
             label = field_name+r'$\/\/('+field_unit+r')$'
@@ -498,9 +500,10 @@
         yfi = pf._get_field_info(*yf)
         x_unit = profile.x.units
         y_unit = profile.field_units[field_y]
+        fractional = profile.fractional
         x_title = self.x_title or self._get_field_label(field_x, xfi, x_unit)
         y_title = self.y_title.get(field_y, None) or \
-                    self._get_field_label(field_y, yfi, y_unit)
+                    self._get_field_label(field_y, yfi, y_unit, fractional)
 
         return (x_title, y_title)
             
@@ -623,13 +626,14 @@
         x_unit = profile.x.units
         y_unit = profile.y.units
         z_unit = profile.field_units[field_z]
+        fractional = profile.fractional
         x_title = self.x_title or self._get_field_label(field_x, xfi, x_unit)
         y_title = self.y_title or self._get_field_label(field_y, yfi, y_unit)
         z_title = self.z_title.get(field_z, None) or \
-                    self._get_field_label(field_z, zfi, z_unit)
+                    self._get_field_label(field_z, zfi, z_unit, fractional)
         return (x_title, y_title, z_title)
 
-    def _get_field_label(self, field, field_info, field_unit):
+    def _get_field_label(self, field, field_info, field_unit, fractional=False):
         field_unit = field_unit.latex_representation()
         field_name = field_info.display_name
         if isinstance(field, tuple): field = field[1]
@@ -639,7 +643,9 @@
         elif field_name.find('$') == -1:
             field_name = field_name.replace(' ','\/')
             field_name = r'$\rm{'+field_name+r'}$'
-        if field_unit is None or field_unit == '':
+        if fractional:
+            label = field_name + r'$\rm{\/Probability\/Density}$'
+        elif field_unit is None or field_unit is '':
             label = field_name
         else:
             label = field_name+r'$\/\/('+field_unit+r')$'

Repository URL: https://bitbucket.org/yt_analysis/yt/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.


More information about the yt-svn mailing list