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

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Tue Jan 10 08:00:32 PST 2017


13 new commits in yt:

https://bitbucket.org/yt_analysis/yt/commits/7b9bbe1566a2/
Changeset:   7b9bbe1566a2
Branch:      yt
User:        atmyers
Date:        2016-09-28 21:53:18+00:00
Summary:     Add sampler type for 1D linear elements.
Affected #:  4 files

diff -r 1d70bf4124996d584483c173e37f29670a73db99 -r 7b9bbe1566a22ebca39f1fc6a2971ddcb9d7acb6 yt/utilities/lib/element_mappings.pxd
--- a/yt/utilities/lib/element_mappings.pxd
+++ b/yt/utilities/lib/element_mappings.pxd
@@ -33,6 +33,21 @@
     cdef int check_mesh_lines(self, double* mapped_coord) nogil
 
 
+cdef class P1Sampler1D(ElementSampler):
+
+    cdef void map_real_to_unit(self,
+                               double* mapped_x,
+                               double* vertices,
+                               double* physical_x) nogil
+
+
+    cdef double sample_at_unit_point(self,
+                                     double* coord,
+                                     double* vals) nogil
+
+    cdef int check_inside(self, double* mapped_coord) nogil
+
+
 cdef class P1Sampler2D(ElementSampler):
 
     cdef void map_real_to_unit(self,

diff -r 1d70bf4124996d584483c173e37f29670a73db99 -r 7b9bbe1566a22ebca39f1fc6a2971ddcb9d7acb6 yt/utilities/lib/element_mappings.pyx
--- a/yt/utilities/lib/element_mappings.pyx
+++ b/yt/utilities/lib/element_mappings.pyx
@@ -115,6 +115,41 @@
         return val
 
 
+cdef class P1Sampler1D(ElementSampler):
+    '''
+
+    This implements sampling inside a linear, 1D element.
+
+    '''
+
+    def __init__(self):
+        super(P1Sampler1D, self).__init__()
+        self.num_mapped_coords = 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef void map_real_to_unit(self, double* mapped_x,
+                               double* vertices, double* physical_x) nogil:
+        mapped_x[0] = -1.0 + 2.0*(physical_x[0] - vertices[0]) / (vertices[1] - vertices[0])
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef double sample_at_unit_point(self,
+                                     double* coord,
+                                     double* vals) nogil:
+        return vals[0] * (1 - coord[0]) / 2.0 + vals[1] * (1.0 + coord[0]) / 2.0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int check_inside(self, double* mapped_coord) nogil:
+        if (fabs(mapped_coord[0]) - 1.0 > self.inclusion_tol):
+            return 0
+        return 1
+
+
 cdef class P1Sampler2D(ElementSampler):
     '''
 
@@ -972,6 +1007,24 @@
 @cython.boundscheck(False)
 @cython.wraparound(False)
 @cython.cdivision(True)
+def test_linear1D_sampler(np.ndarray[np.float64_t, ndim=2] vertices,
+                          np.ndarray[np.float64_t, ndim=1] field_values,
+                          np.ndarray[np.float64_t, ndim=1] physical_x):
+
+    cdef double val
+
+    sampler = P1Sampler1D()
+
+    val = sampler.sample_at_real_point(<double*> vertices.data,
+                                       <double*> field_values.data,
+                                       <double*> physical_x.data)
+
+    return val
+
+
+ at cython.boundscheck(False)
+ at cython.wraparound(False)
+ at cython.cdivision(True)
 def test_tri_sampler(np.ndarray[np.float64_t, ndim=2] vertices,
                      np.ndarray[np.float64_t, ndim=1] field_values,
                      np.ndarray[np.float64_t, ndim=1] physical_x):

diff -r 1d70bf4124996d584483c173e37f29670a73db99 -r 7b9bbe1566a22ebca39f1fc6a2971ddcb9d7acb6 yt/utilities/lib/tests/test_element_mappings.py
--- a/yt/utilities/lib/tests/test_element_mappings.py
+++ b/yt/utilities/lib/tests/test_element_mappings.py
@@ -24,7 +24,8 @@
     test_hex20_sampler, \
     test_wedge_sampler, \
     test_tri2_sampler, \
-    test_tet2_sampler
+    test_tet2_sampler, \
+    test_linear1D_sampler
 
 
 def check_all_vertices(sampler, vertices, field_values):
@@ -37,6 +38,14 @@
         assert_almost_equal(val, field_values[i])
 
 
+def test_P1Sampler1D():
+
+    vertices = np.array([[0.1], [0.3]])
+    field_values = np.array([ 1.,  2.])
+
+    check_all_vertices(test_linear1D_sampler, vertices, field_values)
+
+
 def test_P1Sampler2D():
 
     vertices = np.array([[0.1, 0.2], [0.6, 0.3], [0.2, 0.7]])

diff -r 1d70bf4124996d584483c173e37f29670a73db99 -r 7b9bbe1566a22ebca39f1fc6a2971ddcb9d7acb6 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -235,7 +235,7 @@
             plot_spec = [plot_spec.copy() for p in profiles]
 
         ProfilePlot._initialize_instance(self, profiles, label, plot_spec, y_log)
-        
+
     @validate_plot
     def save(self, name=None, suffix=None, mpl_kwargs=None):
         r"""


https://bitbucket.org/yt_analysis/yt/commits/faa010ec09a1/
Changeset:   faa010ec09a1
Branch:      yt
User:        atmyers
Date:        2016-09-28 21:53:08+00:00
Summary:     patch the element mesh pixelizer to also work with 1D data
Affected #:  1 file

diff -r 9b5937af58578d073179329863c7e220f8ec7df6 -r faa010ec09a1f5c4feb5a0027a02dd494b397804 yt/utilities/lib/pixelization_routines.pyx
--- a/yt/utilities/lib/pixelization_routines.pyx
+++ b/yt/utilities/lib/pixelization_routines.pyx
@@ -25,11 +25,12 @@
 from vec3_ops cimport dot, cross, subtract
 from yt.utilities.lib.element_mappings cimport \
     ElementSampler, \
+    P1Sampler1D, \
+    P1Sampler2D, \
     P1Sampler3D, \
     Q1Sampler3D, \
+    Q1Sampler2D, \
     S2Sampler3D, \
-    P1Sampler2D, \
-    Q1Sampler2D, \
     W1Sampler3D, \
     T2Sampler2D, \
     Tet2Sampler3D
@@ -594,6 +595,8 @@
         sampler = S2Sampler3D()
     elif ndim == 2 and nvertices == 3:
         sampler = P1Sampler2D()
+    elif ndim == 1 and nvertices == 2:
+        sampler = P1Sampler1D()
     elif ndim == 2 and nvertices == 4:
         sampler = Q1Sampler2D()
     elif ndim == 2 and nvertices == 6:
@@ -648,10 +651,13 @@
                 pstart[i] = i64max(<np.int64_t> ((LE[i] - pLE[i])*idds[i]) - 1, 0)
                 pend[i] = i64min(<np.int64_t> ((RE[i] - pLE[i])*idds[i]) + 1, img.shape[i]-1)
 
-            # override for the 2D case
-            if ndim == 2:
+            # override for the low-dimensional case
+            if ndim < 3:
                 pstart[2] = 0
                 pend[2] = 0
+            if ndim < 2:
+                pstart[1] = 0
+                pend[1] = 0
 
             if use == 0:
                 continue


https://bitbucket.org/yt_analysis/yt/commits/2e22ef06260d/
Changeset:   2e22ef06260d
Branch:      yt
User:        atmyers
Date:        2016-09-28 21:53:18+00:00
Summary:     Add sampler type for 1D linear elements.
Affected #:  4 files

diff -r faa010ec09a1f5c4feb5a0027a02dd494b397804 -r 2e22ef06260ded3154b96f49cf0d856589c67132 yt/utilities/lib/element_mappings.pxd
--- a/yt/utilities/lib/element_mappings.pxd
+++ b/yt/utilities/lib/element_mappings.pxd
@@ -33,6 +33,21 @@
     cdef int check_mesh_lines(self, double* mapped_coord) nogil
 
 
+cdef class P1Sampler1D(ElementSampler):
+
+    cdef void map_real_to_unit(self,
+                               double* mapped_x,
+                               double* vertices,
+                               double* physical_x) nogil
+
+
+    cdef double sample_at_unit_point(self,
+                                     double* coord,
+                                     double* vals) nogil
+
+    cdef int check_inside(self, double* mapped_coord) nogil
+
+
 cdef class P1Sampler2D(ElementSampler):
 
     cdef void map_real_to_unit(self,

diff -r faa010ec09a1f5c4feb5a0027a02dd494b397804 -r 2e22ef06260ded3154b96f49cf0d856589c67132 yt/utilities/lib/element_mappings.pyx
--- a/yt/utilities/lib/element_mappings.pyx
+++ b/yt/utilities/lib/element_mappings.pyx
@@ -115,6 +115,41 @@
         return val
 
 
+cdef class P1Sampler1D(ElementSampler):
+    '''
+
+    This implements sampling inside a linear, 1D element.
+
+    '''
+
+    def __init__(self):
+        super(P1Sampler1D, self).__init__()
+        self.num_mapped_coords = 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef void map_real_to_unit(self, double* mapped_x,
+                               double* vertices, double* physical_x) nogil:
+        mapped_x[0] = -1.0 + 2.0*(physical_x[0] - vertices[0]) / (vertices[1] - vertices[0])
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef double sample_at_unit_point(self,
+                                     double* coord,
+                                     double* vals) nogil:
+        return vals[0] * (1 - coord[0]) / 2.0 + vals[1] * (1.0 + coord[0]) / 2.0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int check_inside(self, double* mapped_coord) nogil:
+        if (fabs(mapped_coord[0]) - 1.0 > self.inclusion_tol):
+            return 0
+        return 1
+
+
 cdef class P1Sampler2D(ElementSampler):
     '''
 
@@ -972,6 +1007,24 @@
 @cython.boundscheck(False)
 @cython.wraparound(False)
 @cython.cdivision(True)
+def test_linear1D_sampler(np.ndarray[np.float64_t, ndim=2] vertices,
+                          np.ndarray[np.float64_t, ndim=1] field_values,
+                          np.ndarray[np.float64_t, ndim=1] physical_x):
+
+    cdef double val
+
+    sampler = P1Sampler1D()
+
+    val = sampler.sample_at_real_point(<double*> vertices.data,
+                                       <double*> field_values.data,
+                                       <double*> physical_x.data)
+
+    return val
+
+
+ at cython.boundscheck(False)
+ at cython.wraparound(False)
+ at cython.cdivision(True)
 def test_tri_sampler(np.ndarray[np.float64_t, ndim=2] vertices,
                      np.ndarray[np.float64_t, ndim=1] field_values,
                      np.ndarray[np.float64_t, ndim=1] physical_x):

diff -r faa010ec09a1f5c4feb5a0027a02dd494b397804 -r 2e22ef06260ded3154b96f49cf0d856589c67132 yt/utilities/lib/tests/test_element_mappings.py
--- a/yt/utilities/lib/tests/test_element_mappings.py
+++ b/yt/utilities/lib/tests/test_element_mappings.py
@@ -24,7 +24,8 @@
     test_hex20_sampler, \
     test_wedge_sampler, \
     test_tri2_sampler, \
-    test_tet2_sampler
+    test_tet2_sampler, \
+    test_linear1D_sampler
 
 
 def check_all_vertices(sampler, vertices, field_values):
@@ -37,6 +38,14 @@
         assert_almost_equal(val, field_values[i])
 
 
+def test_P1Sampler1D():
+
+    vertices = np.array([[0.1], [0.3]])
+    field_values = np.array([ 1.,  2.])
+
+    check_all_vertices(test_linear1D_sampler, vertices, field_values)
+
+
 def test_P1Sampler2D():
 
     vertices = np.array([[0.1, 0.2], [0.6, 0.3], [0.2, 0.7]])

diff -r faa010ec09a1f5c4feb5a0027a02dd494b397804 -r 2e22ef06260ded3154b96f49cf0d856589c67132 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -235,7 +235,7 @@
             plot_spec = [plot_spec.copy() for p in profiles]
 
         ProfilePlot._initialize_instance(self, profiles, label, plot_spec, y_log)
-        
+
     @validate_plot
     def save(self, name=None, suffix=None, mpl_kwargs=None):
         r"""


https://bitbucket.org/yt_analysis/yt/commits/b1316c90c0f9/
Changeset:   b1316c90c0f9
Branch:      yt
User:        atmyers
Date:        2016-09-28 22:57:31+00:00
Summary:     merging
Affected #:  5 files

diff -r 098f53627175f611a2b5c45e69efbd5048bb70fb -r b1316c90c0f97d1189bd3920c16ed24969b9206c yt/utilities/lib/element_mappings.pxd
--- a/yt/utilities/lib/element_mappings.pxd
+++ b/yt/utilities/lib/element_mappings.pxd
@@ -33,6 +33,21 @@
     cdef int check_mesh_lines(self, double* mapped_coord) nogil
 
 
+cdef class P1Sampler1D(ElementSampler):
+
+    cdef void map_real_to_unit(self,
+                               double* mapped_x,
+                               double* vertices,
+                               double* physical_x) nogil
+
+
+    cdef double sample_at_unit_point(self,
+                                     double* coord,
+                                     double* vals) nogil
+
+    cdef int check_inside(self, double* mapped_coord) nogil
+
+
 cdef class P1Sampler2D(ElementSampler):
 
     cdef void map_real_to_unit(self,

diff -r 098f53627175f611a2b5c45e69efbd5048bb70fb -r b1316c90c0f97d1189bd3920c16ed24969b9206c yt/utilities/lib/element_mappings.pyx
--- a/yt/utilities/lib/element_mappings.pyx
+++ b/yt/utilities/lib/element_mappings.pyx
@@ -115,6 +115,41 @@
         return val
 
 
+cdef class P1Sampler1D(ElementSampler):
+    '''
+
+    This implements sampling inside a linear, 1D element.
+
+    '''
+
+    def __init__(self):
+        super(P1Sampler1D, self).__init__()
+        self.num_mapped_coords = 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef void map_real_to_unit(self, double* mapped_x,
+                               double* vertices, double* physical_x) nogil:
+        mapped_x[0] = -1.0 + 2.0*(physical_x[0] - vertices[0]) / (vertices[1] - vertices[0])
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef double sample_at_unit_point(self,
+                                     double* coord,
+                                     double* vals) nogil:
+        return vals[0] * (1 - coord[0]) / 2.0 + vals[1] * (1.0 + coord[0]) / 2.0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int check_inside(self, double* mapped_coord) nogil:
+        if (fabs(mapped_coord[0]) - 1.0 > self.inclusion_tol):
+            return 0
+        return 1
+
+
 cdef class P1Sampler2D(ElementSampler):
     '''
 
@@ -972,6 +1007,24 @@
 @cython.boundscheck(False)
 @cython.wraparound(False)
 @cython.cdivision(True)
+def test_linear1D_sampler(np.ndarray[np.float64_t, ndim=2] vertices,
+                          np.ndarray[np.float64_t, ndim=1] field_values,
+                          np.ndarray[np.float64_t, ndim=1] physical_x):
+
+    cdef double val
+
+    sampler = P1Sampler1D()
+
+    val = sampler.sample_at_real_point(<double*> vertices.data,
+                                       <double*> field_values.data,
+                                       <double*> physical_x.data)
+
+    return val
+
+
+ at cython.boundscheck(False)
+ at cython.wraparound(False)
+ at cython.cdivision(True)
 def test_tri_sampler(np.ndarray[np.float64_t, ndim=2] vertices,
                      np.ndarray[np.float64_t, ndim=1] field_values,
                      np.ndarray[np.float64_t, ndim=1] physical_x):

diff -r 098f53627175f611a2b5c45e69efbd5048bb70fb -r b1316c90c0f97d1189bd3920c16ed24969b9206c yt/utilities/lib/pixelization_routines.pyx
--- a/yt/utilities/lib/pixelization_routines.pyx
+++ b/yt/utilities/lib/pixelization_routines.pyx
@@ -25,11 +25,12 @@
 from vec3_ops cimport dot, cross, subtract
 from yt.utilities.lib.element_mappings cimport \
     ElementSampler, \
+    P1Sampler1D, \
+    P1Sampler2D, \
     P1Sampler3D, \
     Q1Sampler3D, \
+    Q1Sampler2D, \
     S2Sampler3D, \
-    P1Sampler2D, \
-    Q1Sampler2D, \
     W1Sampler3D, \
     T2Sampler2D, \
     Tet2Sampler3D
@@ -594,6 +595,8 @@
         sampler = S2Sampler3D()
     elif ndim == 2 and nvertices == 3:
         sampler = P1Sampler2D()
+    elif ndim == 1 and nvertices == 2:
+        sampler = P1Sampler1D()
     elif ndim == 2 and nvertices == 4:
         sampler = Q1Sampler2D()
     elif ndim == 2 and nvertices == 6:
@@ -648,10 +651,13 @@
                 pstart[i] = i64max(<np.int64_t> ((LE[i] - pLE[i])*idds[i]) - 1, 0)
                 pend[i] = i64min(<np.int64_t> ((RE[i] - pLE[i])*idds[i]) + 1, img.shape[i]-1)
 
-            # override for the 2D case
-            if ndim == 2:
+            # override for the low-dimensional case
+            if ndim < 3:
                 pstart[2] = 0
                 pend[2] = 0
+            if ndim < 2:
+                pstart[1] = 0
+                pend[1] = 0
 
             if use == 0:
                 continue

diff -r 098f53627175f611a2b5c45e69efbd5048bb70fb -r b1316c90c0f97d1189bd3920c16ed24969b9206c yt/utilities/lib/tests/test_element_mappings.py
--- a/yt/utilities/lib/tests/test_element_mappings.py
+++ b/yt/utilities/lib/tests/test_element_mappings.py
@@ -24,7 +24,8 @@
     test_hex20_sampler, \
     test_wedge_sampler, \
     test_tri2_sampler, \
-    test_tet2_sampler
+    test_tet2_sampler, \
+    test_linear1D_sampler
 
 
 def check_all_vertices(sampler, vertices, field_values):
@@ -37,6 +38,14 @@
         assert_almost_equal(val, field_values[i])
 
 
+def test_P1Sampler1D():
+
+    vertices = np.array([[0.1], [0.3]])
+    field_values = np.array([ 1.,  2.])
+
+    check_all_vertices(test_linear1D_sampler, vertices, field_values)
+
+
 def test_P1Sampler2D():
 
     vertices = np.array([[0.1, 0.2], [0.6, 0.3], [0.2, 0.7]])

diff -r 098f53627175f611a2b5c45e69efbd5048bb70fb -r b1316c90c0f97d1189bd3920c16ed24969b9206c yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -235,7 +235,7 @@
             plot_spec = [plot_spec.copy() for p in profiles]
 
         ProfilePlot._initialize_instance(self, profiles, label, plot_spec, y_log)
-        
+
     @validate_plot
     def save(self, name=None, suffix=None, mpl_kwargs=None):
         r"""


https://bitbucket.org/yt_analysis/yt/commits/6c1dd626c63a/
Changeset:   6c1dd626c63a
Branch:      yt
User:        atmyers
Date:        2016-09-28 23:09:18+00:00
Summary:     Add sampler type for 1D linear elements.
Affected #:  2 files

diff -r b1316c90c0f97d1189bd3920c16ed24969b9206c -r 6c1dd626c63a069aba3cc68d06a70afdd74e672b yt/frontends/exodus_ii/data_structures.py
--- a/yt/frontends/exodus_ii/data_structures.py
+++ b/yt/frontends/exodus_ii/data_structures.py
@@ -161,11 +161,17 @@
         self.default_field = [f for f in self.field_list 
                               if f[0] == 'connect1'][-1]
 
+        num_pseudo = None
         for mesh in self.index.meshes:
-            num_pseudo = get_num_pseudo_dims(mesh.connectivity_coords)
-            if (num_pseudo > 1 or self.dimensionality < 2):
-                raise RuntimeError("1D unstructured mesh data "
-                                   "are currently not supported.")
+            num_pseudo_dims = get_num_pseudo_dims(mesh.connectivity_coords)
+            if num_pseudo:
+                assert(num_pseudo == num_pseudo_dims)
+            else:
+                num_pseudo = num_pseudo_dims
+
+        self.dimensionality -= num_pseudo
+        self.domain_right_edge = self.domain_right_edge[:self.dimensionality]
+        self.domain_left_edge = self.domain_left_edge[:self.dimensionality]
 
     def _set_code_unit_attributes(self):
         # This is where quantities are created that represent the various
@@ -195,7 +201,7 @@
         self.parameters['nod_names'] = self._get_nod_names()
         self.domain_left_edge, self.domain_right_edge = self._load_domain_edge()
 
-        # set up psuedo-3D for lodim datasets here
+        # set up pseudo-3D for lodim datasets here
         if self.dimensionality == 2:
             self.domain_left_edge = np.append(self.domain_left_edge, 0.0)
             self.domain_right_edge = np.append(self.domain_right_edge, 1.0)

diff -r b1316c90c0f97d1189bd3920c16ed24969b9206c -r 6c1dd626c63a069aba3cc68d06a70afdd74e672b yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -663,6 +663,492 @@
 
         return (x_title, y_title)
 
+
+class LinePlot(object):
+    r"""
+    Create a 1d line plot.
+
+    Given a dataset and a list of fields, this will create a set of
+    one-dimensional plots showing the fields as functions of position.
+
+    Parameters
+    ----------
+
+    ds : :class:`yt.data_objects.api.Dataset`
+        This is the dataset object corresponding to the
+        simulation output to be plotted.
+    fields : str or list
+        The field or fields to be plotted.
+    label : str or list of strings
+        If a string, the label to be put on the line plotted.  If a list,
+        this should be a list of labels, one for each field.
+        Default: None.
+    plot_spec : dict or list of dicts
+        A dictionary or list of dictionaries containing plot keyword 
+        arguments.  For example, dict(color="red", linestyle=":").
+        Default: None.
+    y_log : dict
+        A dictionary containing field:boolean pairs, setting the logarithmic
+        property for that field. May be overridden after instantiation using 
+        set_log.
+        Default: None
+
+    Examples
+    --------
+
+    """
+    y_log = None
+    y_title = None
+    _plot_valid = False
+
+    def __init__(self, ds, fields, label=None, plot_spec=None, y_log=None):
+
+        if isinstance(data_source.ds, YTProfileDataset):
+            profiles = [data_source.ds.profile]
+        else:
+            profiles = [create_profile(data_source, [x_field],
+                                       n_bins=[n_bins],
+                                       fields=ensure_list(y_fields),
+                                       weight_field=weight_field,
+                                       accumulation=accumulation,
+                                       fractional=fractional,
+                                       logs=logs)]
+
+        if plot_spec is None:
+            plot_spec = [dict() for p in profiles]
+        if not isinstance(plot_spec, list):
+            plot_spec = [plot_spec.copy() for p in profiles]
+
+        ProfilePlot._initialize_instance(self, profiles, label, plot_spec, y_log)
+
+    @validate_plot
+    def save(self, name=None, suffix=None, mpl_kwargs=None):
+        r"""
+        Saves a 1d profile plot.
+
+        Parameters
+        ----------
+        name : str
+            The output file keyword.
+        suffix : string
+            Specify the image type by its suffix. If not specified, the output
+            type will be inferred from the filename. Defaults to PNG.
+        mpl_kwargs : dict
+            A dict of keyword arguments to be passed to matplotlib.
+        """
+        if not self._plot_valid:
+            self._setup_plots()
+        unique = set(self.plots.values())
+        if len(unique) < len(self.plots):
+            iters = izip(range(len(unique)), sorted(unique))
+        else:
+            iters = iteritems(self.plots)
+        if not suffix:
+            suffix = "png"
+        suffix = ".%s" % suffix
+        fullname = False
+        if name is None:
+            if len(self.profiles) == 1:
+                prefix = self.profiles[0].ds
+            else:
+                prefix = "Multi-data"
+            name = "%s%s" % (prefix, suffix)
+        else:
+            sfx = get_image_suffix(name)
+            if sfx != '':
+                suffix = sfx
+                prefix = name[:name.rfind(suffix)]
+                fullname = True
+            else:
+                prefix = name
+        xfn = self.profiles[0].x_field
+        if isinstance(xfn, tuple):
+            xfn = xfn[1]
+        fns = []
+        for uid, plot in iters:
+            if isinstance(uid, tuple):
+                uid = uid[1]
+            if fullname:
+                fns.append("%s%s" % (prefix, suffix))
+            else:
+                fns.append("%s_1d-Profile_%s_%s%s" % (prefix, xfn, uid, suffix))
+            mylog.info("Saving %s", fns[-1])
+            with matplotlib_style_context():
+                plot.save(fns[-1], mpl_kwargs=mpl_kwargs)
+        return fns
+
+    @validate_plot
+    def show(self):
+        r"""This will send any existing plots to the IPython notebook.
+
+        If yt is being run from within an IPython session, and it is able to
+        determine this, this function will send any existing plots to the
+        notebook for display.
+
+        If yt can't determine if it's inside an IPython session, it will raise
+        YTNotInsideNotebook.
+
+        Examples
+        --------
+
+        >>> import yt
+        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
+        >>> pp = ProfilePlot(ds.all_data(), 'density', 'temperature')
+        >>> pp.show()
+
+        """
+        if "__IPYTHON__" in dir(builtins):
+            api_version = get_ipython_api_version()
+            if api_version in ('0.10', '0.11'):
+                self._send_zmq()
+            else:
+                from IPython.display import display
+                display(self)
+        else:
+            raise YTNotInsideNotebook
+
+    @validate_plot
+    def _repr_html_(self):
+        """Return an html representation of the plot object. Will display as a
+        png for each WindowPlotMPL instance in self.plots"""
+        from . import _mpl_imports as mpl
+        ret = ''
+        unique = set(self.figures.values())
+        if len(unique) < len(self.figures):
+            iters = izip(range(len(unique)), sorted(unique))
+        else:
+            iters = iteritems(self.figures)
+        for uid, fig in iters:
+            canvas = mpl.FigureCanvasAgg(fig)
+            f = BytesIO()
+            with matplotlib_style_context():
+                canvas.print_figure(f)
+            f.seek(0)
+            img = base64.b64encode(f.read()).decode()
+            ret += r'<img style="max-width:100%%;max-height:100%%;" ' \
+                   r'src="data:image/png;base64,{0}"><br>'.format(img)
+        return ret
+
+    def _setup_plots(self):
+        if self._plot_valid is True:
+            return
+        for f in self.axes:
+            self.axes[f].cla()
+        for i, profile in enumerate(self.profiles):
+            for field, field_data in profile.items():
+                self.axes[field].plot(np.array(profile.x), np.array(field_data),
+                                      label=self.label[i], **self.plot_spec[i])
+
+        for (fname, axes), profile in zip(self.axes.items(), self.profiles):
+            xscale, yscale = self._get_field_log(fname, profile)
+            xtitle, ytitle = self._get_field_title(fname, profile)
+            axes.set_xscale(xscale)
+            axes.set_yscale(yscale)
+            axes.set_xlabel(xtitle)
+            axes.set_ylabel(ytitle)
+            axes.set_ylim(*self.axes.ylim[fname])
+            if any(self.label):
+                axes.legend(loc="best")
+        self._set_font_properties()
+        self._plot_valid = True
+
+    @classmethod
+    def _initialize_instance(cls, obj, profiles, labels, plot_specs, y_log):
+        from matplotlib.font_manager import FontProperties
+        obj._font_properties = FontProperties(family='stixgeneral', size=18)
+        obj._font_color = None
+        obj.profiles = ensure_list(profiles)
+        obj.x_log = None
+        obj.y_log = {}
+        if y_log is not None:
+            for field, log in y_log.items():
+                field, = obj.profiles[0].data_source._determine_fields([field])
+                obj.y_log[field] = log
+        obj.y_title = {}
+        obj.label = sanitize_label(labels, len(obj.profiles))
+        if plot_specs is None:
+            plot_specs = [dict() for p in obj.profiles]
+        obj.plot_spec = plot_specs
+        obj.plots = PlotContainer()
+        obj.figures = FigureContainer(obj.plots)
+        obj.axes = AxesContainer(obj.plots)
+        obj._setup_plots()
+        return obj
+
+    @classmethod
+    def from_profiles(cls, profiles, labels=None, plot_specs=None, y_log=None):
+        r"""
+        Instantiate a ProfilePlot object from a list of profiles
+        created with :func:`~yt.data_objects.profiles.create_profile`.
+
+        Parameters
+        ----------
+        profiles : a profile or list of profiles
+            A single profile or list of profile objects created with
+            :func:`~yt.data_objects.profiles.create_profile`.
+        labels : list of strings
+            A list of labels for each profile to be overplotted.
+            Default: None.
+        plot_specs : list of dicts
+            A list of dictionaries containing plot keyword
+            arguments.  For example, [dict(color="red", linestyle=":")].
+            Default: None.
+
+        Examples
+        --------
+
+        >>> from yt import simulation
+        >>> es = simulation("AMRCosmology.enzo", "Enzo")
+        >>> es.get_time_series()
+
+        >>> profiles = []
+        >>> labels = []
+        >>> plot_specs = []
+        >>> for ds in es[-4:]:
+        ...     ad = ds.all_data()
+        ...     profiles.append(create_profile(ad, ["Density"],
+        ...                                    fields=["Temperature",
+        ...                                            "x-velocity"]))
+        ...     labels.append(ds.current_redshift)
+        ...     plot_specs.append(dict(linestyle="--", alpha=0.7))
+        >>>
+        >>> plot = ProfilePlot.from_profiles(profiles, labels=labels,
+        ...                                  plot_specs=plot_specs)
+        >>> plot.save()
+        
+        """
+        if labels is not None and len(profiles) != len(labels):
+            raise RuntimeError("Profiles list and labels list must be the same size.")
+        if plot_specs is not None and len(plot_specs) != len(profiles):
+            raise RuntimeError("Profiles list and plot_specs list must be the same size.")
+        obj = cls.__new__(cls)
+        return cls._initialize_instance(obj, profiles, labels, plot_specs, y_log)
+
+    @invalidate_plot
+    def set_line_property(self, property, value, index=None):
+        r"""
+        Set properties for one or all lines to be plotted.
+
+        Parameters
+        ----------
+        property : str
+            The line property to be set.
+        value : str, int, float
+            The value to set for the line property.
+        index : int
+            The index of the profile in the list of profiles to be 
+            changed.  If None, change all plotted lines.
+            Default : None.
+
+        Examples
+        --------
+
+        Change all the lines in a plot
+        plot.set_line_property("linestyle", "-")
+
+        Change a single line.
+        plot.set_line_property("linewidth", 4, index=0)
+        
+        """
+        if index is None:
+            specs = self.plot_spec
+        else:
+            specs = [self.plot_spec[index]]
+        for spec in specs:
+            spec[property] = value
+        return self
+
+    @invalidate_plot
+    def set_log(self, field, log):
+        """set a field to log or linear.
+
+        Parameters
+        ----------
+        field : string
+            the field to set a transform
+        log : boolean
+            Log on/off.
+        """
+        if field == "all":
+            self.x_log = log
+            for field in list(self.profiles[0].field_data.keys()):
+                self.y_log[field] = log
+        else:
+            field, = self.profiles[0].data_source._determine_fields([field])
+            if field == self.profiles[0].x_field:
+                self.x_log = log
+            elif field in self.profiles[0].field_data:
+                self.y_log[field] = log
+            else:
+                raise KeyError("Field %s not in profile plot!" % (field))
+        return self
+
+    @invalidate_plot
+    def set_unit(self, field, unit):
+        """Sets a new unit for the requested field
+
+        Parameters
+        ----------
+        field : string
+           The name of the field that is to be changed.
+
+        new_unit : string or Unit object
+           The name of the new unit.
+        """
+        for profile in self.profiles:
+            if field == profile.x_field[1]:
+                profile.set_x_unit(unit)
+            elif field in self.profiles[0].field_map:
+                profile.set_field_unit(field, unit)
+            else:
+                raise KeyError("Field %s not in profile plot!" % (field))
+        return self
+
+    @invalidate_plot
+    def set_xlim(self, xmin=None, xmax=None):
+        """Sets the limits of the bin field
+
+        Parameters
+        ----------
+        
+        xmin : float or None
+          The new x minimum.  Defaults to None, which leaves the xmin
+          unchanged.
+
+        xmax : float or None
+          The new x maximum.  Defaults to None, which leaves the xmax
+          unchanged.
+
+        Examples
+        --------
+
+        >>> import yt
+        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
+        >>> pp = yt.ProfilePlot(ds.all_data(), 'density', 'temperature')
+        >>> pp.set_xlim(1e-29, 1e-24)
+        >>> pp.save()
+
+        """
+        for i, p in enumerate(self.profiles):
+            if xmin is None:
+                xmi = p.x_bins.min()
+            else:
+                xmi = xmin
+            if xmax is None:
+                xma = p.x_bins.max()
+            else:
+                xma = xmax
+            extrema = {p.x_field: ((xmi, str(p.x.units)), (xma, str(p.x.units)))}
+            units = {p.x_field: str(p.x.units)}
+            if self.x_log is None:
+                logs = None
+            else:
+                logs = {p.x_field: self.x_log}
+            for field in p.field_map.values():
+                units[field] = str(p.field_data[field].units)
+            self.profiles[i] = \
+                create_profile(p.data_source, p.x_field,
+                               n_bins=len(p.x_bins)-1,
+                               fields=list(p.field_map.values()),
+                               weight_field=p.weight_field,
+                               accumulation=p.accumulation,
+                               fractional=p.fractional,
+                               logs=logs,
+                               extrema=extrema, units=units)
+        return self
+
+    @invalidate_plot
+    def set_ylim(self, field, ymin=None, ymax=None):
+        """Sets the plot limits for the specified field we are binning.
+
+        Parameters
+        ----------
+
+        field : string or field tuple
+
+        The field that we want to adjust the plot limits for.
+        
+        ymin : float or None
+          The new y minimum.  Defaults to None, which leaves the ymin
+          unchanged.
+
+        ymax : float or None
+          The new y maximum.  Defaults to None, which leaves the ymax
+          unchanged.
+
+        Examples
+        --------
+
+        >>> import yt
+        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
+        >>> pp = yt.ProfilePlot(ds.all_data(), 'density', ['temperature', 'x-velocity'])
+        >>> pp.set_ylim('temperature', 1e4, 1e6)
+        >>> pp.save()
+
+        """
+        if field is 'all':
+            fields = list(self.axes.keys())
+        else:
+            fields = ensure_list(field)
+        for profile in self.profiles:
+            for field in profile.data_source._determine_fields(fields):
+                if field in profile.field_map:
+                    field = profile.field_map[field]
+                self.axes.ylim[field] = (ymin, ymax)
+                # Continue on to the next profile.
+                break
+        return self
+
+    def _set_font_properties(self):
+        for f in self.plots:
+            self.plots[f]._set_font_properties(
+                self._font_properties, self._font_color)
+
+    def _get_field_log(self, field_y, profile):
+        yfi = profile.field_info[field_y]
+        if self.x_log is None:
+            x_log = profile.x_log
+        else:
+            x_log = self.x_log
+        if field_y in self.y_log:
+            y_log = self.y_log[field_y]
+        else:
+            y_log = yfi.take_log
+        scales = {True: 'log', False: 'linear'}
+        return scales[x_log], scales[y_log]
+
+    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]
+        if field_name is None:
+            field_name = r'$\rm{'+field+r'}$'
+            field_name = r'$\rm{'+field.replace('_','\ ').title()+r'}$'
+        elif field_name.find('$') == -1:
+            field_name = field_name.replace(' ','\ ')
+            field_name = r'$\rm{'+field_name+r'}$'
+        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')$'
+        return label
+
+    def _get_field_title(self, field_y, profile):
+        field_x = profile.x_field
+        xfi = profile.field_info[field_x]
+        yfi = profile.field_info[field_y]
+        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, fractional)
+
+        return (x_title, y_title)
+
+
 class PhasePlot(ImagePlotContainer):
     r"""
     Create a 2d profile (phase) plot from a data source or from 


https://bitbucket.org/yt_analysis/yt/commits/474bbda62243/
Changeset:   474bbda62243
Branch:      yt
User:        atmyers
Date:        2016-09-28 23:21:39+00:00
Summary:     trying to handle datasets with some dimensions set to zero.
Affected #:  1 file

diff -r 6c1dd626c63a069aba3cc68d06a70afdd74e672b -r 474bbda62243c09877986bc537c4f5959f830aec yt/frontends/exodus_ii/data_structures.py
--- a/yt/frontends/exodus_ii/data_structures.py
+++ b/yt/frontends/exodus_ii/data_structures.py
@@ -170,8 +170,9 @@
                 num_pseudo = num_pseudo_dims
 
         self.dimensionality -= num_pseudo
-        self.domain_right_edge = self.domain_right_edge[:self.dimensionality]
-        self.domain_left_edge = self.domain_left_edge[:self.dimensionality]
+        for i in range(self.dimensionality, 3):
+            self.domain_left_edge[i] = 0.0
+            self.domain_right_edge[i] = 1.0
 
     def _set_code_unit_attributes(self):
         # This is where quantities are created that represent the various


https://bitbucket.org/yt_analysis/yt/commits/95454c7d941f/
Changeset:   95454c7d941f
Branch:      yt
User:        atmyers
Date:        2016-09-28 23:56:06+00:00
Summary:     handling the pseudo-3D for datasets where one or more of the dimensions are zeroed out.
Affected #:  1 file

diff -r 474bbda62243c09877986bc537c4f5959f830aec -r 95454c7d941f75f8461e166c94af83932edd2b27 yt/frontends/exodus_ii/data_structures.py
--- a/yt/frontends/exodus_ii/data_structures.py
+++ b/yt/frontends/exodus_ii/data_structures.py
@@ -161,19 +161,6 @@
         self.default_field = [f for f in self.field_list 
                               if f[0] == 'connect1'][-1]
 
-        num_pseudo = None
-        for mesh in self.index.meshes:
-            num_pseudo_dims = get_num_pseudo_dims(mesh.connectivity_coords)
-            if num_pseudo:
-                assert(num_pseudo == num_pseudo_dims)
-            else:
-                num_pseudo = num_pseudo_dims
-
-        self.dimensionality -= num_pseudo
-        for i in range(self.dimensionality, 3):
-            self.domain_left_edge[i] = 0.0
-            self.domain_right_edge[i] = 1.0
-
     def _set_code_unit_attributes(self):
         # This is where quantities are created that represent the various
         # on-disk units.  These are the currently available quantities which
@@ -201,12 +188,6 @@
         self.parameters['elem_names'] = self._get_elem_names()
         self.parameters['nod_names'] = self._get_nod_names()
         self.domain_left_edge, self.domain_right_edge = self._load_domain_edge()
-
-        # set up pseudo-3D for lodim datasets here
-        if self.dimensionality == 2:
-            self.domain_left_edge = np.append(self.domain_left_edge, 0.0)
-            self.domain_right_edge = np.append(self.domain_right_edge, 1.0)
-
         self.periodicity = (False, False, False)
 
         # These attributes don't really make sense for unstructured
@@ -377,6 +358,18 @@
         width = ma - mi
         mi -= 0.1 * width
         ma += 0.1 * width
+
+        # set up pseudo-3D for lodim datasets here
+        for _ in range(self.dimensionality, 3):
+            mi = np.append(mi, 0.0)
+            ma = np.append(ma, 1.0)
+
+        num_pseudo_dims = get_num_pseudo_dims(coords)
+        self.dimensionality -= num_pseudo_dims
+        for i in range(self.dimensionality, 3):
+            mi[i] = 0.0
+            ma[i] = 1.0
+        
         return mi, ma
 
     @classmethod


https://bitbucket.org/yt_analysis/yt/commits/e928ec89f0bc/
Changeset:   e928ec89f0bc
Branch:      yt
User:        atmyers
Date:        2016-09-30 20:26:02+00:00
Summary:     some work towards implementing 1D plots for unstructured mesh datasets
Affected #:  1 file

diff -r 95454c7d941f75f8461e166c94af83932edd2b27 -r e928ec89f0bc1afe7e8827f5a8e1ce0707f55f78 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -44,6 +44,8 @@
     get_image_suffix, \
     get_ipython_api_version, \
     matplotlib_style_context
+from yt.utilities.lib.pixelization_routines import pixelize_element_mesh
+from yt.data_objects.unstructured_mesh import SemiStructuredMesh
 
 def get_canvas(name):
     from . import _mpl_imports as mpl
@@ -701,30 +703,64 @@
     y_title = None
     _plot_valid = False
 
-    def __init__(self, ds, fields, label=None, plot_spec=None, y_log=None):
+    def __init__(self, ds, fields, label=None, plot_spec=None, y_log=None, resolution=800):
 
-        if isinstance(data_source.ds, YTProfileDataset):
-            profiles = [data_source.ds.profile]
-        else:
-            profiles = [create_profile(data_source, [x_field],
-                                       n_bins=[n_bins],
-                                       fields=ensure_list(y_fields),
-                                       weight_field=weight_field,
-                                       accumulation=accumulation,
-                                       fractional=fractional,
-                                       logs=logs)]
+        self.ds = ds
+        self.x_field = 'x'
+        index = ds.index
+        assert(ds.dimensionality == 1)
+        assert(hasattr(index, 'meshes') and not isinstance(index.meshes[0], SemiStructuredMesh))
+        
+        buff_size = [resolution, 1, 1]
+
+        self.fields = ensure_list(fields)
+        self.y_data = []
+        for field in self.fields:
+            ftype, fname = field
+            mesh_id = int(ftype[-1]) - 1
+            mesh = index.meshes[mesh_id]
+            coords = mesh.connectivity_coords
+            indices = mesh.connectivity_indices
+            offset = mesh._index_offset
+            ad = ds.all_data()
+            field_data = ad[field]
+            extents = [[coords.min(), coords.max()]]
+
+            dds = (extents[0][1] - extents[0][0]) / buff_size[0]
+            x = np.linspace(extents[0][0] + 0.5*dds, extents[0][1] - 0.5*dds, buff_size[0])
+            self.x_data = x
+
+            img = pixelize_element_mesh(coords, indices, buff_size, 
+                                        field_data, extents, index_offset=offset)
+            self.y_data.append(img[:, 0, 0])
 
         if plot_spec is None:
-            plot_spec = [dict() for p in profiles]
+            plot_spec = [dict() for f in self.fields]
         if not isinstance(plot_spec, list):
-            plot_spec = [plot_spec.copy() for p in profiles]
+            plot_spec = [plot_spec.copy() for f in self.fields]
 
-        ProfilePlot._initialize_instance(self, profiles, label, plot_spec, y_log)
+        self.plot_spec = plot_spec
+        from matplotlib.font_manager import FontProperties
+        self._font_properties = FontProperties(family='stixgeneral', size=18)
+        self._font_color = None
+        self.x_log = None
+        self.y_log = {}
+        if y_log is not None:
+            for field, log in y_log.items():
+                field, = ad._determine_fields([field])
+                self.y_log[field] = log
+        self.y_title = {}
+        self.label = sanitize_label(label, len(self.y_data))
+        self.plots = PlotContainer()
+        self.figures = FigureContainer(self.plots)
+        self.axes = AxesContainer(self.plots)
+        self._setup_plots()
+
 
     @validate_plot
     def save(self, name=None, suffix=None, mpl_kwargs=None):
         r"""
-        Saves a 1d profile plot.
+        Saves a 1d line plot.
 
         Parameters
         ----------
@@ -748,8 +784,8 @@
         suffix = ".%s" % suffix
         fullname = False
         if name is None:
-            if len(self.profiles) == 1:
-                prefix = self.profiles[0].ds
+            if len(self.y_data) == 1:
+                prefix = self.ds
             else:
                 prefix = "Multi-data"
             name = "%s%s" % (prefix, suffix)
@@ -761,7 +797,7 @@
                 fullname = True
             else:
                 prefix = name
-        xfn = self.profiles[0].x_field
+        xfn = self.x_field
         if isinstance(xfn, tuple):
             xfn = xfn[1]
         fns = []
@@ -834,10 +870,9 @@
             return
         for f in self.axes:
             self.axes[f].cla()
-        for i, profile in enumerate(self.profiles):
-            for field, field_data in profile.items():
-                self.axes[field].plot(np.array(profile.x), np.array(field_data),
-                                      label=self.label[i], **self.plot_spec[i])
+        for i, field in enumerate(self.fields):
+            self.axes[field].plot(self.x_data, self.y_data[i],
+                                  label=self.label[i], **self.plot_spec[i])
 
         for (fname, axes), profile in zip(self.axes.items(), self.profiles):
             xscale, yscale = self._get_field_log(fname, profile)
@@ -852,78 +887,6 @@
         self._set_font_properties()
         self._plot_valid = True
 
-    @classmethod
-    def _initialize_instance(cls, obj, profiles, labels, plot_specs, y_log):
-        from matplotlib.font_manager import FontProperties
-        obj._font_properties = FontProperties(family='stixgeneral', size=18)
-        obj._font_color = None
-        obj.profiles = ensure_list(profiles)
-        obj.x_log = None
-        obj.y_log = {}
-        if y_log is not None:
-            for field, log in y_log.items():
-                field, = obj.profiles[0].data_source._determine_fields([field])
-                obj.y_log[field] = log
-        obj.y_title = {}
-        obj.label = sanitize_label(labels, len(obj.profiles))
-        if plot_specs is None:
-            plot_specs = [dict() for p in obj.profiles]
-        obj.plot_spec = plot_specs
-        obj.plots = PlotContainer()
-        obj.figures = FigureContainer(obj.plots)
-        obj.axes = AxesContainer(obj.plots)
-        obj._setup_plots()
-        return obj
-
-    @classmethod
-    def from_profiles(cls, profiles, labels=None, plot_specs=None, y_log=None):
-        r"""
-        Instantiate a ProfilePlot object from a list of profiles
-        created with :func:`~yt.data_objects.profiles.create_profile`.
-
-        Parameters
-        ----------
-        profiles : a profile or list of profiles
-            A single profile or list of profile objects created with
-            :func:`~yt.data_objects.profiles.create_profile`.
-        labels : list of strings
-            A list of labels for each profile to be overplotted.
-            Default: None.
-        plot_specs : list of dicts
-            A list of dictionaries containing plot keyword
-            arguments.  For example, [dict(color="red", linestyle=":")].
-            Default: None.
-
-        Examples
-        --------
-
-        >>> from yt import simulation
-        >>> es = simulation("AMRCosmology.enzo", "Enzo")
-        >>> es.get_time_series()
-
-        >>> profiles = []
-        >>> labels = []
-        >>> plot_specs = []
-        >>> for ds in es[-4:]:
-        ...     ad = ds.all_data()
-        ...     profiles.append(create_profile(ad, ["Density"],
-        ...                                    fields=["Temperature",
-        ...                                            "x-velocity"]))
-        ...     labels.append(ds.current_redshift)
-        ...     plot_specs.append(dict(linestyle="--", alpha=0.7))
-        >>>
-        >>> plot = ProfilePlot.from_profiles(profiles, labels=labels,
-        ...                                  plot_specs=plot_specs)
-        >>> plot.save()
-        
-        """
-        if labels is not None and len(profiles) != len(labels):
-            raise RuntimeError("Profiles list and labels list must be the same size.")
-        if plot_specs is not None and len(plot_specs) != len(profiles):
-            raise RuntimeError("Profiles list and plot_specs list must be the same size.")
-        obj = cls.__new__(cls)
-        return cls._initialize_instance(obj, profiles, labels, plot_specs, y_log)
-
     @invalidate_plot
     def set_line_property(self, property, value, index=None):
         r"""


https://bitbucket.org/yt_analysis/yt/commits/11f718845127/
Changeset:   11f718845127
Branch:      yt
User:        atmyers
Date:        2016-09-30 21:20:34+00:00
Summary:     merging
Affected #:  3 files

diff -r 7b9bbe1566a22ebca39f1fc6a2971ddcb9d7acb6 -r 11f718845127fd99e48f936424a5a5dd0b9d9b8d yt/frontends/exodus_ii/data_structures.py
--- a/yt/frontends/exodus_ii/data_structures.py
+++ b/yt/frontends/exodus_ii/data_structures.py
@@ -161,12 +161,6 @@
         self.default_field = [f for f in self.field_list 
                               if f[0] == 'connect1'][-1]
 
-        for mesh in self.index.meshes:
-            num_pseudo = get_num_pseudo_dims(mesh.connectivity_coords)
-            if (num_pseudo > 1 or self.dimensionality < 2):
-                raise RuntimeError("1D unstructured mesh data "
-                                   "are currently not supported.")
-
     def _set_code_unit_attributes(self):
         # This is where quantities are created that represent the various
         # on-disk units.  These are the currently available quantities which
@@ -194,12 +188,6 @@
         self.parameters['elem_names'] = self._get_elem_names()
         self.parameters['nod_names'] = self._get_nod_names()
         self.domain_left_edge, self.domain_right_edge = self._load_domain_edge()
-
-        # set up psuedo-3D for lodim datasets here
-        if self.dimensionality == 2:
-            self.domain_left_edge = np.append(self.domain_left_edge, 0.0)
-            self.domain_right_edge = np.append(self.domain_right_edge, 1.0)
-
         self.periodicity = (False, False, False)
 
         # These attributes don't really make sense for unstructured
@@ -370,6 +358,18 @@
         width = ma - mi
         mi -= 0.1 * width
         ma += 0.1 * width
+
+        # set up pseudo-3D for lodim datasets here
+        for _ in range(self.dimensionality, 3):
+            mi = np.append(mi, 0.0)
+            ma = np.append(ma, 1.0)
+
+        num_pseudo_dims = get_num_pseudo_dims(coords)
+        self.dimensionality -= num_pseudo_dims
+        for i in range(self.dimensionality, 3):
+            mi[i] = 0.0
+            ma[i] = 1.0
+        
         return mi, ma
 
     @classmethod

diff -r 7b9bbe1566a22ebca39f1fc6a2971ddcb9d7acb6 -r 11f718845127fd99e48f936424a5a5dd0b9d9b8d yt/utilities/lib/pixelization_routines.pyx
--- a/yt/utilities/lib/pixelization_routines.pyx
+++ b/yt/utilities/lib/pixelization_routines.pyx
@@ -25,11 +25,12 @@
 from vec3_ops cimport dot, cross, subtract
 from yt.utilities.lib.element_mappings cimport \
     ElementSampler, \
+    P1Sampler1D, \
+    P1Sampler2D, \
     P1Sampler3D, \
     Q1Sampler3D, \
+    Q1Sampler2D, \
     S2Sampler3D, \
-    P1Sampler2D, \
-    Q1Sampler2D, \
     W1Sampler3D, \
     T2Sampler2D, \
     Tet2Sampler3D
@@ -604,6 +605,8 @@
         sampler = S2Sampler3D()
     elif ndim == 2 and nvertices == 3:
         sampler = P1Sampler2D()
+    elif ndim == 1 and nvertices == 2:
+        sampler = P1Sampler1D()
     elif ndim == 2 and nvertices == 4:
         sampler = Q1Sampler2D()
     elif ndim == 2 and nvertices == 6:
@@ -658,10 +661,13 @@
                 pstart[i] = i64max(<np.int64_t> ((LE[i] - pLE[i])*idds[i]) - 1, 0)
                 pend[i] = i64min(<np.int64_t> ((RE[i] - pLE[i])*idds[i]) + 1, img.shape[i]-1)
 
-            # override for the 2D case
-            if ndim == 2:
+            # override for the low-dimensional case
+            if ndim < 3:
                 pstart[2] = 0
                 pend[2] = 0
+            if ndim < 2:
+                pstart[1] = 0
+                pend[1] = 0
 
             if use == 0:
                 continue

diff -r 7b9bbe1566a22ebca39f1fc6a2971ddcb9d7acb6 -r 11f718845127fd99e48f936424a5a5dd0b9d9b8d yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -44,6 +44,8 @@
     get_image_suffix, \
     get_ipython_api_version, \
     matplotlib_style_context
+from yt.utilities.lib.pixelization_routines import pixelize_element_mesh
+from yt.data_objects.unstructured_mesh import SemiStructuredMesh
 
 def get_canvas(name):
     from . import _mpl_imports as mpl
@@ -663,6 +665,453 @@
 
         return (x_title, y_title)
 
+
+class LinePlot(object):
+    r"""
+    Create a 1d line plot.
+
+    Given a dataset and a list of fields, this will create a set of
+    one-dimensional plots showing the fields as functions of position.
+
+    Parameters
+    ----------
+
+    ds : :class:`yt.data_objects.api.Dataset`
+        This is the dataset object corresponding to the
+        simulation output to be plotted.
+    fields : str or list
+        The field or fields to be plotted.
+    label : str or list of strings
+        If a string, the label to be put on the line plotted.  If a list,
+        this should be a list of labels, one for each field.
+        Default: None.
+    plot_spec : dict or list of dicts
+        A dictionary or list of dictionaries containing plot keyword 
+        arguments.  For example, dict(color="red", linestyle=":").
+        Default: None.
+    y_log : dict
+        A dictionary containing field:boolean pairs, setting the logarithmic
+        property for that field. May be overridden after instantiation using 
+        set_log.
+        Default: None
+
+    Examples
+    --------
+
+    """
+    y_log = None
+    y_title = None
+    _plot_valid = False
+
+    def __init__(self, ds, fields, label=None, plot_spec=None, y_log=None, resolution=800):
+
+        self.ds = ds
+        self.x_field = 'x'
+        index = ds.index
+        assert(ds.dimensionality == 1)
+        assert(hasattr(index, 'meshes') and not isinstance(index.meshes[0], SemiStructuredMesh))
+        
+        buff_size = [resolution, 1, 1]
+
+        self.fields = ensure_list(fields)
+        self.y_data = []
+        for field in self.fields:
+            ftype, fname = field
+            mesh_id = int(ftype[-1]) - 1
+            mesh = index.meshes[mesh_id]
+            coords = mesh.connectivity_coords
+            indices = mesh.connectivity_indices
+            offset = mesh._index_offset
+            ad = ds.all_data()
+            field_data = ad[field]
+            extents = [[coords.min(), coords.max()]]
+
+            dds = (extents[0][1] - extents[0][0]) / buff_size[0]
+            x = np.linspace(extents[0][0] + 0.5*dds, extents[0][1] - 0.5*dds, buff_size[0])
+            self.x_data = x
+
+            img = pixelize_element_mesh(coords, indices, buff_size, 
+                                        field_data, extents, index_offset=offset)
+            self.y_data.append(img[:, 0, 0])
+
+        if plot_spec is None:
+            plot_spec = [dict() for f in self.fields]
+        if not isinstance(plot_spec, list):
+            plot_spec = [plot_spec.copy() for f in self.fields]
+
+        self.plot_spec = plot_spec
+        from matplotlib.font_manager import FontProperties
+        self._font_properties = FontProperties(family='stixgeneral', size=18)
+        self._font_color = None
+        self.x_log = None
+        self.y_log = {}
+        if y_log is not None:
+            for field, log in y_log.items():
+                field, = ad._determine_fields([field])
+                self.y_log[field] = log
+        self.y_title = {}
+        self.label = sanitize_label(label, len(self.y_data))
+        self.plots = PlotContainer()
+        self.figures = FigureContainer(self.plots)
+        self.axes = AxesContainer(self.plots)
+        self._setup_plots()
+
+
+    @validate_plot
+    def save(self, name=None, suffix=None, mpl_kwargs=None):
+        r"""
+        Saves a 1d line plot.
+
+        Parameters
+        ----------
+        name : str
+            The output file keyword.
+        suffix : string
+            Specify the image type by its suffix. If not specified, the output
+            type will be inferred from the filename. Defaults to PNG.
+        mpl_kwargs : dict
+            A dict of keyword arguments to be passed to matplotlib.
+        """
+        if not self._plot_valid:
+            self._setup_plots()
+        unique = set(self.plots.values())
+        if len(unique) < len(self.plots):
+            iters = izip(range(len(unique)), sorted(unique))
+        else:
+            iters = iteritems(self.plots)
+        if not suffix:
+            suffix = "png"
+        suffix = ".%s" % suffix
+        fullname = False
+        if name is None:
+            if len(self.y_data) == 1:
+                prefix = self.ds
+            else:
+                prefix = "Multi-data"
+            name = "%s%s" % (prefix, suffix)
+        else:
+            sfx = get_image_suffix(name)
+            if sfx != '':
+                suffix = sfx
+                prefix = name[:name.rfind(suffix)]
+                fullname = True
+            else:
+                prefix = name
+        xfn = self.x_field
+        if isinstance(xfn, tuple):
+            xfn = xfn[1]
+        fns = []
+        for uid, plot in iters:
+            if isinstance(uid, tuple):
+                uid = uid[1]
+            if fullname:
+                fns.append("%s%s" % (prefix, suffix))
+            else:
+                fns.append("%s_1d-Profile_%s_%s%s" % (prefix, xfn, uid, suffix))
+            mylog.info("Saving %s", fns[-1])
+            with matplotlib_style_context():
+                plot.save(fns[-1], mpl_kwargs=mpl_kwargs)
+        return fns
+
+    @validate_plot
+    def show(self):
+        r"""This will send any existing plots to the IPython notebook.
+
+        If yt is being run from within an IPython session, and it is able to
+        determine this, this function will send any existing plots to the
+        notebook for display.
+
+        If yt can't determine if it's inside an IPython session, it will raise
+        YTNotInsideNotebook.
+
+        Examples
+        --------
+
+        >>> import yt
+        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
+        >>> pp = ProfilePlot(ds.all_data(), 'density', 'temperature')
+        >>> pp.show()
+
+        """
+        if "__IPYTHON__" in dir(builtins):
+            api_version = get_ipython_api_version()
+            if api_version in ('0.10', '0.11'):
+                self._send_zmq()
+            else:
+                from IPython.display import display
+                display(self)
+        else:
+            raise YTNotInsideNotebook
+
+    @validate_plot
+    def _repr_html_(self):
+        """Return an html representation of the plot object. Will display as a
+        png for each WindowPlotMPL instance in self.plots"""
+        from . import _mpl_imports as mpl
+        ret = ''
+        unique = set(self.figures.values())
+        if len(unique) < len(self.figures):
+            iters = izip(range(len(unique)), sorted(unique))
+        else:
+            iters = iteritems(self.figures)
+        for uid, fig in iters:
+            canvas = mpl.FigureCanvasAgg(fig)
+            f = BytesIO()
+            with matplotlib_style_context():
+                canvas.print_figure(f)
+            f.seek(0)
+            img = base64.b64encode(f.read()).decode()
+            ret += r'<img style="max-width:100%%;max-height:100%%;" ' \
+                   r'src="data:image/png;base64,{0}"><br>'.format(img)
+        return ret
+
+    def _setup_plots(self):
+        if self._plot_valid is True:
+            return
+        for f in self.axes:
+            self.axes[f].cla()
+        for i, field in enumerate(self.fields):
+            self.axes[field].plot(self.x_data, self.y_data[i],
+                                  label=self.label[i], **self.plot_spec[i])
+
+        for (fname, axes), profile in zip(self.axes.items(), self.profiles):
+            xscale, yscale = self._get_field_log(fname, profile)
+            xtitle, ytitle = self._get_field_title(fname, profile)
+            axes.set_xscale(xscale)
+            axes.set_yscale(yscale)
+            axes.set_xlabel(xtitle)
+            axes.set_ylabel(ytitle)
+            axes.set_ylim(*self.axes.ylim[fname])
+            if any(self.label):
+                axes.legend(loc="best")
+        self._set_font_properties()
+        self._plot_valid = True
+
+    @invalidate_plot
+    def set_line_property(self, property, value, index=None):
+        r"""
+        Set properties for one or all lines to be plotted.
+
+        Parameters
+        ----------
+        property : str
+            The line property to be set.
+        value : str, int, float
+            The value to set for the line property.
+        index : int
+            The index of the profile in the list of profiles to be 
+            changed.  If None, change all plotted lines.
+            Default : None.
+
+        Examples
+        --------
+
+        Change all the lines in a plot
+        plot.set_line_property("linestyle", "-")
+
+        Change a single line.
+        plot.set_line_property("linewidth", 4, index=0)
+        
+        """
+        if index is None:
+            specs = self.plot_spec
+        else:
+            specs = [self.plot_spec[index]]
+        for spec in specs:
+            spec[property] = value
+        return self
+
+    @invalidate_plot
+    def set_log(self, field, log):
+        """set a field to log or linear.
+
+        Parameters
+        ----------
+        field : string
+            the field to set a transform
+        log : boolean
+            Log on/off.
+        """
+        if field == "all":
+            self.x_log = log
+            for field in list(self.profiles[0].field_data.keys()):
+                self.y_log[field] = log
+        else:
+            field, = self.profiles[0].data_source._determine_fields([field])
+            if field == self.profiles[0].x_field:
+                self.x_log = log
+            elif field in self.profiles[0].field_data:
+                self.y_log[field] = log
+            else:
+                raise KeyError("Field %s not in profile plot!" % (field))
+        return self
+
+    @invalidate_plot
+    def set_unit(self, field, unit):
+        """Sets a new unit for the requested field
+
+        Parameters
+        ----------
+        field : string
+           The name of the field that is to be changed.
+
+        new_unit : string or Unit object
+           The name of the new unit.
+        """
+        for profile in self.profiles:
+            if field == profile.x_field[1]:
+                profile.set_x_unit(unit)
+            elif field in self.profiles[0].field_map:
+                profile.set_field_unit(field, unit)
+            else:
+                raise KeyError("Field %s not in profile plot!" % (field))
+        return self
+
+    @invalidate_plot
+    def set_xlim(self, xmin=None, xmax=None):
+        """Sets the limits of the bin field
+
+        Parameters
+        ----------
+        
+        xmin : float or None
+          The new x minimum.  Defaults to None, which leaves the xmin
+          unchanged.
+
+        xmax : float or None
+          The new x maximum.  Defaults to None, which leaves the xmax
+          unchanged.
+
+        Examples
+        --------
+
+        >>> import yt
+        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
+        >>> pp = yt.ProfilePlot(ds.all_data(), 'density', 'temperature')
+        >>> pp.set_xlim(1e-29, 1e-24)
+        >>> pp.save()
+
+        """
+        for i, p in enumerate(self.profiles):
+            if xmin is None:
+                xmi = p.x_bins.min()
+            else:
+                xmi = xmin
+            if xmax is None:
+                xma = p.x_bins.max()
+            else:
+                xma = xmax
+            extrema = {p.x_field: ((xmi, str(p.x.units)), (xma, str(p.x.units)))}
+            units = {p.x_field: str(p.x.units)}
+            if self.x_log is None:
+                logs = None
+            else:
+                logs = {p.x_field: self.x_log}
+            for field in p.field_map.values():
+                units[field] = str(p.field_data[field].units)
+            self.profiles[i] = \
+                create_profile(p.data_source, p.x_field,
+                               n_bins=len(p.x_bins)-1,
+                               fields=list(p.field_map.values()),
+                               weight_field=p.weight_field,
+                               accumulation=p.accumulation,
+                               fractional=p.fractional,
+                               logs=logs,
+                               extrema=extrema, units=units)
+        return self
+
+    @invalidate_plot
+    def set_ylim(self, field, ymin=None, ymax=None):
+        """Sets the plot limits for the specified field we are binning.
+
+        Parameters
+        ----------
+
+        field : string or field tuple
+
+        The field that we want to adjust the plot limits for.
+        
+        ymin : float or None
+          The new y minimum.  Defaults to None, which leaves the ymin
+          unchanged.
+
+        ymax : float or None
+          The new y maximum.  Defaults to None, which leaves the ymax
+          unchanged.
+
+        Examples
+        --------
+
+        >>> import yt
+        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
+        >>> pp = yt.ProfilePlot(ds.all_data(), 'density', ['temperature', 'x-velocity'])
+        >>> pp.set_ylim('temperature', 1e4, 1e6)
+        >>> pp.save()
+
+        """
+        if field is 'all':
+            fields = list(self.axes.keys())
+        else:
+            fields = ensure_list(field)
+        for profile in self.profiles:
+            for field in profile.data_source._determine_fields(fields):
+                if field in profile.field_map:
+                    field = profile.field_map[field]
+                self.axes.ylim[field] = (ymin, ymax)
+                # Continue on to the next profile.
+                break
+        return self
+
+    def _set_font_properties(self):
+        for f in self.plots:
+            self.plots[f]._set_font_properties(
+                self._font_properties, self._font_color)
+
+    def _get_field_log(self, field_y, profile):
+        yfi = profile.field_info[field_y]
+        if self.x_log is None:
+            x_log = profile.x_log
+        else:
+            x_log = self.x_log
+        if field_y in self.y_log:
+            y_log = self.y_log[field_y]
+        else:
+            y_log = yfi.take_log
+        scales = {True: 'log', False: 'linear'}
+        return scales[x_log], scales[y_log]
+
+    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]
+        if field_name is None:
+            field_name = r'$\rm{'+field+r'}$'
+            field_name = r'$\rm{'+field.replace('_','\ ').title()+r'}$'
+        elif field_name.find('$') == -1:
+            field_name = field_name.replace(' ','\ ')
+            field_name = r'$\rm{'+field_name+r'}$'
+        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')$'
+        return label
+
+    def _get_field_title(self, field_y, profile):
+        field_x = profile.x_field
+        xfi = profile.field_info[field_x]
+        yfi = profile.field_info[field_y]
+        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, fractional)
+
+        return (x_title, y_title)
+
+
 class PhasePlot(ImagePlotContainer):
     r"""
     Create a 2d profile (phase) plot from a data source or from 


https://bitbucket.org/yt_analysis/yt/commits/1801e3dd0cf5/
Changeset:   1801e3dd0cf5
Branch:      yt
User:        atmyers
Date:        2016-09-30 21:21:50+00:00
Summary:     Removing LinePlot for now.
Affected #:  1 file

diff -r 11f718845127fd99e48f936424a5a5dd0b9d9b8d -r 1801e3dd0cf5cb7996ebfe15f6ff3848538c2638 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -666,452 +666,6 @@
         return (x_title, y_title)
 
 
-class LinePlot(object):
-    r"""
-    Create a 1d line plot.
-
-    Given a dataset and a list of fields, this will create a set of
-    one-dimensional plots showing the fields as functions of position.
-
-    Parameters
-    ----------
-
-    ds : :class:`yt.data_objects.api.Dataset`
-        This is the dataset object corresponding to the
-        simulation output to be plotted.
-    fields : str or list
-        The field or fields to be plotted.
-    label : str or list of strings
-        If a string, the label to be put on the line plotted.  If a list,
-        this should be a list of labels, one for each field.
-        Default: None.
-    plot_spec : dict or list of dicts
-        A dictionary or list of dictionaries containing plot keyword 
-        arguments.  For example, dict(color="red", linestyle=":").
-        Default: None.
-    y_log : dict
-        A dictionary containing field:boolean pairs, setting the logarithmic
-        property for that field. May be overridden after instantiation using 
-        set_log.
-        Default: None
-
-    Examples
-    --------
-
-    """
-    y_log = None
-    y_title = None
-    _plot_valid = False
-
-    def __init__(self, ds, fields, label=None, plot_spec=None, y_log=None, resolution=800):
-
-        self.ds = ds
-        self.x_field = 'x'
-        index = ds.index
-        assert(ds.dimensionality == 1)
-        assert(hasattr(index, 'meshes') and not isinstance(index.meshes[0], SemiStructuredMesh))
-        
-        buff_size = [resolution, 1, 1]
-
-        self.fields = ensure_list(fields)
-        self.y_data = []
-        for field in self.fields:
-            ftype, fname = field
-            mesh_id = int(ftype[-1]) - 1
-            mesh = index.meshes[mesh_id]
-            coords = mesh.connectivity_coords
-            indices = mesh.connectivity_indices
-            offset = mesh._index_offset
-            ad = ds.all_data()
-            field_data = ad[field]
-            extents = [[coords.min(), coords.max()]]
-
-            dds = (extents[0][1] - extents[0][0]) / buff_size[0]
-            x = np.linspace(extents[0][0] + 0.5*dds, extents[0][1] - 0.5*dds, buff_size[0])
-            self.x_data = x
-
-            img = pixelize_element_mesh(coords, indices, buff_size, 
-                                        field_data, extents, index_offset=offset)
-            self.y_data.append(img[:, 0, 0])
-
-        if plot_spec is None:
-            plot_spec = [dict() for f in self.fields]
-        if not isinstance(plot_spec, list):
-            plot_spec = [plot_spec.copy() for f in self.fields]
-
-        self.plot_spec = plot_spec
-        from matplotlib.font_manager import FontProperties
-        self._font_properties = FontProperties(family='stixgeneral', size=18)
-        self._font_color = None
-        self.x_log = None
-        self.y_log = {}
-        if y_log is not None:
-            for field, log in y_log.items():
-                field, = ad._determine_fields([field])
-                self.y_log[field] = log
-        self.y_title = {}
-        self.label = sanitize_label(label, len(self.y_data))
-        self.plots = PlotContainer()
-        self.figures = FigureContainer(self.plots)
-        self.axes = AxesContainer(self.plots)
-        self._setup_plots()
-
-
-    @validate_plot
-    def save(self, name=None, suffix=None, mpl_kwargs=None):
-        r"""
-        Saves a 1d line plot.
-
-        Parameters
-        ----------
-        name : str
-            The output file keyword.
-        suffix : string
-            Specify the image type by its suffix. If not specified, the output
-            type will be inferred from the filename. Defaults to PNG.
-        mpl_kwargs : dict
-            A dict of keyword arguments to be passed to matplotlib.
-        """
-        if not self._plot_valid:
-            self._setup_plots()
-        unique = set(self.plots.values())
-        if len(unique) < len(self.plots):
-            iters = izip(range(len(unique)), sorted(unique))
-        else:
-            iters = iteritems(self.plots)
-        if not suffix:
-            suffix = "png"
-        suffix = ".%s" % suffix
-        fullname = False
-        if name is None:
-            if len(self.y_data) == 1:
-                prefix = self.ds
-            else:
-                prefix = "Multi-data"
-            name = "%s%s" % (prefix, suffix)
-        else:
-            sfx = get_image_suffix(name)
-            if sfx != '':
-                suffix = sfx
-                prefix = name[:name.rfind(suffix)]
-                fullname = True
-            else:
-                prefix = name
-        xfn = self.x_field
-        if isinstance(xfn, tuple):
-            xfn = xfn[1]
-        fns = []
-        for uid, plot in iters:
-            if isinstance(uid, tuple):
-                uid = uid[1]
-            if fullname:
-                fns.append("%s%s" % (prefix, suffix))
-            else:
-                fns.append("%s_1d-Profile_%s_%s%s" % (prefix, xfn, uid, suffix))
-            mylog.info("Saving %s", fns[-1])
-            with matplotlib_style_context():
-                plot.save(fns[-1], mpl_kwargs=mpl_kwargs)
-        return fns
-
-    @validate_plot
-    def show(self):
-        r"""This will send any existing plots to the IPython notebook.
-
-        If yt is being run from within an IPython session, and it is able to
-        determine this, this function will send any existing plots to the
-        notebook for display.
-
-        If yt can't determine if it's inside an IPython session, it will raise
-        YTNotInsideNotebook.
-
-        Examples
-        --------
-
-        >>> import yt
-        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
-        >>> pp = ProfilePlot(ds.all_data(), 'density', 'temperature')
-        >>> pp.show()
-
-        """
-        if "__IPYTHON__" in dir(builtins):
-            api_version = get_ipython_api_version()
-            if api_version in ('0.10', '0.11'):
-                self._send_zmq()
-            else:
-                from IPython.display import display
-                display(self)
-        else:
-            raise YTNotInsideNotebook
-
-    @validate_plot
-    def _repr_html_(self):
-        """Return an html representation of the plot object. Will display as a
-        png for each WindowPlotMPL instance in self.plots"""
-        from . import _mpl_imports as mpl
-        ret = ''
-        unique = set(self.figures.values())
-        if len(unique) < len(self.figures):
-            iters = izip(range(len(unique)), sorted(unique))
-        else:
-            iters = iteritems(self.figures)
-        for uid, fig in iters:
-            canvas = mpl.FigureCanvasAgg(fig)
-            f = BytesIO()
-            with matplotlib_style_context():
-                canvas.print_figure(f)
-            f.seek(0)
-            img = base64.b64encode(f.read()).decode()
-            ret += r'<img style="max-width:100%%;max-height:100%%;" ' \
-                   r'src="data:image/png;base64,{0}"><br>'.format(img)
-        return ret
-
-    def _setup_plots(self):
-        if self._plot_valid is True:
-            return
-        for f in self.axes:
-            self.axes[f].cla()
-        for i, field in enumerate(self.fields):
-            self.axes[field].plot(self.x_data, self.y_data[i],
-                                  label=self.label[i], **self.plot_spec[i])
-
-        for (fname, axes), profile in zip(self.axes.items(), self.profiles):
-            xscale, yscale = self._get_field_log(fname, profile)
-            xtitle, ytitle = self._get_field_title(fname, profile)
-            axes.set_xscale(xscale)
-            axes.set_yscale(yscale)
-            axes.set_xlabel(xtitle)
-            axes.set_ylabel(ytitle)
-            axes.set_ylim(*self.axes.ylim[fname])
-            if any(self.label):
-                axes.legend(loc="best")
-        self._set_font_properties()
-        self._plot_valid = True
-
-    @invalidate_plot
-    def set_line_property(self, property, value, index=None):
-        r"""
-        Set properties for one or all lines to be plotted.
-
-        Parameters
-        ----------
-        property : str
-            The line property to be set.
-        value : str, int, float
-            The value to set for the line property.
-        index : int
-            The index of the profile in the list of profiles to be 
-            changed.  If None, change all plotted lines.
-            Default : None.
-
-        Examples
-        --------
-
-        Change all the lines in a plot
-        plot.set_line_property("linestyle", "-")
-
-        Change a single line.
-        plot.set_line_property("linewidth", 4, index=0)
-        
-        """
-        if index is None:
-            specs = self.plot_spec
-        else:
-            specs = [self.plot_spec[index]]
-        for spec in specs:
-            spec[property] = value
-        return self
-
-    @invalidate_plot
-    def set_log(self, field, log):
-        """set a field to log or linear.
-
-        Parameters
-        ----------
-        field : string
-            the field to set a transform
-        log : boolean
-            Log on/off.
-        """
-        if field == "all":
-            self.x_log = log
-            for field in list(self.profiles[0].field_data.keys()):
-                self.y_log[field] = log
-        else:
-            field, = self.profiles[0].data_source._determine_fields([field])
-            if field == self.profiles[0].x_field:
-                self.x_log = log
-            elif field in self.profiles[0].field_data:
-                self.y_log[field] = log
-            else:
-                raise KeyError("Field %s not in profile plot!" % (field))
-        return self
-
-    @invalidate_plot
-    def set_unit(self, field, unit):
-        """Sets a new unit for the requested field
-
-        Parameters
-        ----------
-        field : string
-           The name of the field that is to be changed.
-
-        new_unit : string or Unit object
-           The name of the new unit.
-        """
-        for profile in self.profiles:
-            if field == profile.x_field[1]:
-                profile.set_x_unit(unit)
-            elif field in self.profiles[0].field_map:
-                profile.set_field_unit(field, unit)
-            else:
-                raise KeyError("Field %s not in profile plot!" % (field))
-        return self
-
-    @invalidate_plot
-    def set_xlim(self, xmin=None, xmax=None):
-        """Sets the limits of the bin field
-
-        Parameters
-        ----------
-        
-        xmin : float or None
-          The new x minimum.  Defaults to None, which leaves the xmin
-          unchanged.
-
-        xmax : float or None
-          The new x maximum.  Defaults to None, which leaves the xmax
-          unchanged.
-
-        Examples
-        --------
-
-        >>> import yt
-        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
-        >>> pp = yt.ProfilePlot(ds.all_data(), 'density', 'temperature')
-        >>> pp.set_xlim(1e-29, 1e-24)
-        >>> pp.save()
-
-        """
-        for i, p in enumerate(self.profiles):
-            if xmin is None:
-                xmi = p.x_bins.min()
-            else:
-                xmi = xmin
-            if xmax is None:
-                xma = p.x_bins.max()
-            else:
-                xma = xmax
-            extrema = {p.x_field: ((xmi, str(p.x.units)), (xma, str(p.x.units)))}
-            units = {p.x_field: str(p.x.units)}
-            if self.x_log is None:
-                logs = None
-            else:
-                logs = {p.x_field: self.x_log}
-            for field in p.field_map.values():
-                units[field] = str(p.field_data[field].units)
-            self.profiles[i] = \
-                create_profile(p.data_source, p.x_field,
-                               n_bins=len(p.x_bins)-1,
-                               fields=list(p.field_map.values()),
-                               weight_field=p.weight_field,
-                               accumulation=p.accumulation,
-                               fractional=p.fractional,
-                               logs=logs,
-                               extrema=extrema, units=units)
-        return self
-
-    @invalidate_plot
-    def set_ylim(self, field, ymin=None, ymax=None):
-        """Sets the plot limits for the specified field we are binning.
-
-        Parameters
-        ----------
-
-        field : string or field tuple
-
-        The field that we want to adjust the plot limits for.
-        
-        ymin : float or None
-          The new y minimum.  Defaults to None, which leaves the ymin
-          unchanged.
-
-        ymax : float or None
-          The new y maximum.  Defaults to None, which leaves the ymax
-          unchanged.
-
-        Examples
-        --------
-
-        >>> import yt
-        >>> ds = yt.load('IsolatedGalaxy/galaxy0030/galaxy0030')
-        >>> pp = yt.ProfilePlot(ds.all_data(), 'density', ['temperature', 'x-velocity'])
-        >>> pp.set_ylim('temperature', 1e4, 1e6)
-        >>> pp.save()
-
-        """
-        if field is 'all':
-            fields = list(self.axes.keys())
-        else:
-            fields = ensure_list(field)
-        for profile in self.profiles:
-            for field in profile.data_source._determine_fields(fields):
-                if field in profile.field_map:
-                    field = profile.field_map[field]
-                self.axes.ylim[field] = (ymin, ymax)
-                # Continue on to the next profile.
-                break
-        return self
-
-    def _set_font_properties(self):
-        for f in self.plots:
-            self.plots[f]._set_font_properties(
-                self._font_properties, self._font_color)
-
-    def _get_field_log(self, field_y, profile):
-        yfi = profile.field_info[field_y]
-        if self.x_log is None:
-            x_log = profile.x_log
-        else:
-            x_log = self.x_log
-        if field_y in self.y_log:
-            y_log = self.y_log[field_y]
-        else:
-            y_log = yfi.take_log
-        scales = {True: 'log', False: 'linear'}
-        return scales[x_log], scales[y_log]
-
-    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]
-        if field_name is None:
-            field_name = r'$\rm{'+field+r'}$'
-            field_name = r'$\rm{'+field.replace('_','\ ').title()+r'}$'
-        elif field_name.find('$') == -1:
-            field_name = field_name.replace(' ','\ ')
-            field_name = r'$\rm{'+field_name+r'}$'
-        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')$'
-        return label
-
-    def _get_field_title(self, field_y, profile):
-        field_x = profile.x_field
-        xfi = profile.field_info[field_x]
-        yfi = profile.field_info[field_y]
-        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, fractional)
-
-        return (x_title, y_title)
-
-
 class PhasePlot(ImagePlotContainer):
     r"""
     Create a 2d profile (phase) plot from a data source or from 


https://bitbucket.org/yt_analysis/yt/commits/1e9adb9b1369/
Changeset:   1e9adb9b1369
Branch:      yt
User:        atmyers
Date:        2016-09-30 21:23:58+00:00
Summary:     removing some more changes from profile_plotter
Affected #:  1 file

diff -r 1801e3dd0cf5cb7996ebfe15f6ff3848538c2638 -r 1e9adb9b1369941687b74ca73843eed3fe509fe7 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -44,8 +44,6 @@
     get_image_suffix, \
     get_ipython_api_version, \
     matplotlib_style_context
-from yt.utilities.lib.pixelization_routines import pixelize_element_mesh
-from yt.data_objects.unstructured_mesh import SemiStructuredMesh
 
 def get_canvas(name):
     from . import _mpl_imports as mpl
@@ -237,7 +235,7 @@
             plot_spec = [plot_spec.copy() for p in profiles]
 
         ProfilePlot._initialize_instance(self, profiles, label, plot_spec, y_log)
-
+    
     @validate_plot
     def save(self, name=None, suffix=None, mpl_kwargs=None):
         r"""
@@ -665,7 +663,6 @@
 
         return (x_title, y_title)
 
-
 class PhasePlot(ImagePlotContainer):
     r"""
     Create a 2d profile (phase) plot from a data source or from 


https://bitbucket.org/yt_analysis/yt/commits/f569db8df4c5/
Changeset:   f569db8df4c5
Branch:      yt
User:        atmyers
Date:        2016-09-30 21:30:04+00:00
Summary:     also handle 1D unstructured datasets in the streaming frontend.
Affected #:  2 files

diff -r 1e9adb9b1369941687b74ca73843eed3fe509fe7 -r f569db8df4c57b8672233a8230eeaec687cc968f yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -1749,11 +1749,6 @@
     """
 
     dimensionality = coordinates.shape[1]
-    num_pseudo = get_num_pseudo_dims(coordinates)
-    if (num_pseudo > 1 or dimensionality < 2):
-        raise RuntimeError("1D unstructured mesh data "
-                           "are currently not supported.")
-
     domain_dimensions = np.ones(3, "int32") * 2
     nprocs = 1
 
@@ -1788,8 +1783,17 @@
                  coordinates[:,i].max() + 0.1 * abs(coordinates[:,i].max())]
                 for i in range(dimensionality)]
 
-    if dimensionality == 2:
+    if dimensionality < 3:
         bbox.append([0.0, 1.0])
+    if dimensionality < 2:
+        bbox.append([0.0, 1.0])
+
+    # handle pseudo-dims here
+    num_pseudo_dims = get_num_pseudo_dims(coordinates)
+    dimensionality -= num_pseudo_dims
+    for i in range(dimensionality, 3):
+        bbox[i][0] = 0.0
+        bbox[i][1] = 1.0
 
     bbox = np.array(bbox, dtype=np.float64)
     domain_left_edge = np.array(bbox[:, 0], 'float64')

diff -r 1e9adb9b1369941687b74ca73843eed3fe509fe7 -r f569db8df4c57b8672233a8230eeaec687cc968f yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -235,7 +235,7 @@
             plot_spec = [plot_spec.copy() for p in profiles]
 
         ProfilePlot._initialize_instance(self, profiles, label, plot_spec, y_log)
-    
+
     @validate_plot
     def save(self, name=None, suffix=None, mpl_kwargs=None):
         r"""


https://bitbucket.org/yt_analysis/yt/commits/98bb0abc0b14/
Changeset:   98bb0abc0b14
Branch:      yt
User:        ngoldbaum
Date:        2017-01-10 16:00:03+00:00
Summary:     Merged in atmyers/yt (pull request #2402)

Some work towards 1D unstructured plotting support
Affected #:  7 files

diff -r 175a73a087238b633f6cc92f7f28d94878cd3217 -r 98bb0abc0b1421cba1c16df4ecca2ebd861d36d6 yt/frontends/exodus_ii/data_structures.py
--- a/yt/frontends/exodus_ii/data_structures.py
+++ b/yt/frontends/exodus_ii/data_structures.py
@@ -161,12 +161,6 @@
         self.default_field = [f for f in self.field_list 
                               if f[0] == 'connect1'][-1]
 
-        for mesh in self.index.meshes:
-            num_pseudo = get_num_pseudo_dims(mesh.connectivity_coords)
-            if (num_pseudo > 1 or self.dimensionality < 2):
-                raise RuntimeError("1D unstructured mesh data "
-                                   "are currently not supported.")
-
     def _set_code_unit_attributes(self):
         # This is where quantities are created that represent the various
         # on-disk units.  These are the currently available quantities which
@@ -194,12 +188,6 @@
         self.parameters['elem_names'] = self._get_elem_names()
         self.parameters['nod_names'] = self._get_nod_names()
         self.domain_left_edge, self.domain_right_edge = self._load_domain_edge()
-
-        # set up psuedo-3D for lodim datasets here
-        if self.dimensionality == 2:
-            self.domain_left_edge = np.append(self.domain_left_edge, 0.0)
-            self.domain_right_edge = np.append(self.domain_right_edge, 1.0)
-
         self.periodicity = (False, False, False)
 
         # These attributes don't really make sense for unstructured
@@ -370,6 +358,18 @@
         width = ma - mi
         mi -= 0.1 * width
         ma += 0.1 * width
+
+        # set up pseudo-3D for lodim datasets here
+        for _ in range(self.dimensionality, 3):
+            mi = np.append(mi, 0.0)
+            ma = np.append(ma, 1.0)
+
+        num_pseudo_dims = get_num_pseudo_dims(coords)
+        self.dimensionality -= num_pseudo_dims
+        for i in range(self.dimensionality, 3):
+            mi[i] = 0.0
+            ma[i] = 1.0
+        
         return mi, ma
 
     @classmethod

diff -r 175a73a087238b633f6cc92f7f28d94878cd3217 -r 98bb0abc0b1421cba1c16df4ecca2ebd861d36d6 yt/frontends/stream/data_structures.py
--- a/yt/frontends/stream/data_structures.py
+++ b/yt/frontends/stream/data_structures.py
@@ -1750,11 +1750,6 @@
     """
 
     dimensionality = coordinates.shape[1]
-    num_pseudo = get_num_pseudo_dims(coordinates)
-    if (num_pseudo > 1 or dimensionality < 2):
-        raise RuntimeError("1D unstructured mesh data "
-                           "are currently not supported.")
-
     domain_dimensions = np.ones(3, "int32") * 2
     nprocs = 1
 
@@ -1789,8 +1784,17 @@
                  coordinates[:,i].max() + 0.1 * abs(coordinates[:,i].max())]
                 for i in range(dimensionality)]
 
-    if dimensionality == 2:
+    if dimensionality < 3:
         bbox.append([0.0, 1.0])
+    if dimensionality < 2:
+        bbox.append([0.0, 1.0])
+
+    # handle pseudo-dims here
+    num_pseudo_dims = get_num_pseudo_dims(coordinates)
+    dimensionality -= num_pseudo_dims
+    for i in range(dimensionality, 3):
+        bbox[i][0] = 0.0
+        bbox[i][1] = 1.0
 
     bbox = np.array(bbox, dtype=np.float64)
     domain_left_edge = np.array(bbox[:, 0], 'float64')

diff -r 175a73a087238b633f6cc92f7f28d94878cd3217 -r 98bb0abc0b1421cba1c16df4ecca2ebd861d36d6 yt/utilities/lib/element_mappings.pxd
--- a/yt/utilities/lib/element_mappings.pxd
+++ b/yt/utilities/lib/element_mappings.pxd
@@ -33,6 +33,21 @@
     cdef int check_mesh_lines(self, double* mapped_coord) nogil
 
 
+cdef class P1Sampler1D(ElementSampler):
+
+    cdef void map_real_to_unit(self,
+                               double* mapped_x,
+                               double* vertices,
+                               double* physical_x) nogil
+
+
+    cdef double sample_at_unit_point(self,
+                                     double* coord,
+                                     double* vals) nogil
+
+    cdef int check_inside(self, double* mapped_coord) nogil
+
+
 cdef class P1Sampler2D(ElementSampler):
 
     cdef void map_real_to_unit(self,

diff -r 175a73a087238b633f6cc92f7f28d94878cd3217 -r 98bb0abc0b1421cba1c16df4ecca2ebd861d36d6 yt/utilities/lib/element_mappings.pyx
--- a/yt/utilities/lib/element_mappings.pyx
+++ b/yt/utilities/lib/element_mappings.pyx
@@ -115,6 +115,41 @@
         return val
 
 
+cdef class P1Sampler1D(ElementSampler):
+    '''
+
+    This implements sampling inside a linear, 1D element.
+
+    '''
+
+    def __init__(self):
+        super(P1Sampler1D, self).__init__()
+        self.num_mapped_coords = 1
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef void map_real_to_unit(self, double* mapped_x,
+                               double* vertices, double* physical_x) nogil:
+        mapped_x[0] = -1.0 + 2.0*(physical_x[0] - vertices[0]) / (vertices[1] - vertices[0])
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef double sample_at_unit_point(self,
+                                     double* coord,
+                                     double* vals) nogil:
+        return vals[0] * (1 - coord[0]) / 2.0 + vals[1] * (1.0 + coord[0]) / 2.0
+
+    @cython.boundscheck(False)
+    @cython.wraparound(False)
+    @cython.cdivision(True)
+    cdef int check_inside(self, double* mapped_coord) nogil:
+        if (fabs(mapped_coord[0]) - 1.0 > self.inclusion_tol):
+            return 0
+        return 1
+
+
 cdef class P1Sampler2D(ElementSampler):
     '''
 
@@ -1005,6 +1040,24 @@
 @cython.boundscheck(False)
 @cython.wraparound(False)
 @cython.cdivision(True)
+def test_linear1D_sampler(np.ndarray[np.float64_t, ndim=2] vertices,
+                          np.ndarray[np.float64_t, ndim=1] field_values,
+                          np.ndarray[np.float64_t, ndim=1] physical_x):
+
+    cdef double val
+
+    sampler = P1Sampler1D()
+
+    val = sampler.sample_at_real_point(<double*> vertices.data,
+                                       <double*> field_values.data,
+                                       <double*> physical_x.data)
+
+    return val
+
+
+ at cython.boundscheck(False)
+ at cython.wraparound(False)
+ at cython.cdivision(True)
 def test_tri_sampler(np.ndarray[np.float64_t, ndim=2] vertices,
                      np.ndarray[np.float64_t, ndim=1] field_values,
                      np.ndarray[np.float64_t, ndim=1] physical_x):

diff -r 175a73a087238b633f6cc92f7f28d94878cd3217 -r 98bb0abc0b1421cba1c16df4ecca2ebd861d36d6 yt/utilities/lib/pixelization_routines.pyx
--- a/yt/utilities/lib/pixelization_routines.pyx
+++ b/yt/utilities/lib/pixelization_routines.pyx
@@ -25,11 +25,12 @@
 from vec3_ops cimport dot, cross, subtract
 from yt.utilities.lib.element_mappings cimport \
     ElementSampler, \
+    P1Sampler1D, \
+    P1Sampler2D, \
     P1Sampler3D, \
     Q1Sampler3D, \
+    Q1Sampler2D, \
     S2Sampler3D, \
-    P1Sampler2D, \
-    Q1Sampler2D, \
     W1Sampler3D, \
     T2Sampler2D, \
     Tet2Sampler3D
@@ -604,6 +605,8 @@
         sampler = S2Sampler3D()
     elif ndim == 2 and nvertices == 3:
         sampler = P1Sampler2D()
+    elif ndim == 1 and nvertices == 2:
+        sampler = P1Sampler1D()
     elif ndim == 2 and nvertices == 4:
         sampler = Q1Sampler2D()
     elif ndim == 2 and nvertices == 6:
@@ -658,10 +661,13 @@
                 pstart[i] = i64max(<np.int64_t> ((LE[i] - pLE[i])*idds[i]) - 1, 0)
                 pend[i] = i64min(<np.int64_t> ((RE[i] - pLE[i])*idds[i]) + 1, img.shape[i]-1)
 
-            # override for the 2D case
-            if ndim == 2:
+            # override for the low-dimensional case
+            if ndim < 3:
                 pstart[2] = 0
                 pend[2] = 0
+            if ndim < 2:
+                pstart[1] = 0
+                pend[1] = 0
 
             if use == 0:
                 continue

diff -r 175a73a087238b633f6cc92f7f28d94878cd3217 -r 98bb0abc0b1421cba1c16df4ecca2ebd861d36d6 yt/utilities/lib/tests/test_element_mappings.py
--- a/yt/utilities/lib/tests/test_element_mappings.py
+++ b/yt/utilities/lib/tests/test_element_mappings.py
@@ -24,7 +24,8 @@
     test_hex20_sampler, \
     test_wedge_sampler, \
     test_tri2_sampler, \
-    test_tet2_sampler
+    test_tet2_sampler, \
+    test_linear1D_sampler
 
 
 def check_all_vertices(sampler, vertices, field_values):
@@ -37,6 +38,14 @@
         assert_almost_equal(val, field_values[i])
 
 
+def test_P1Sampler1D():
+
+    vertices = np.array([[0.1], [0.3]])
+    field_values = np.array([ 1.,  2.])
+
+    check_all_vertices(test_linear1D_sampler, vertices, field_values)
+
+
 def test_P1Sampler2D():
 
     vertices = np.array([[0.1, 0.2], [0.6, 0.3], [0.2, 0.7]])

diff -r 175a73a087238b633f6cc92f7f28d94878cd3217 -r 98bb0abc0b1421cba1c16df4ecca2ebd861d36d6 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -234,7 +234,7 @@
             plot_spec = [plot_spec.copy() for p in profiles]
 
         ProfilePlot._initialize_instance(self, profiles, label, plot_spec, y_log)
-        
+
     @validate_plot
     def save(self, name=None, suffix=None, mpl_kwargs=None):
         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