Repository: yt-project/yt

Issue:
Off-Axis Projections do not work on Cut Regions (in at least Ramses)
<!--To help us understand and resolve your issue, please fill out the form to
the best of your ability.-->
<!--You can feel free to delete the sections that do not apply.-->

### Bug report

**Bug summary**

Off-Axis Projections work for Ramses datasets for geometric containers. However, using a cut region does not work, giving the error: 
   AttributeError: 'OctreeSubsetBlockSlicePosition' object has no attribute '_field_parameter_state'

Cut regions need to inherit from YTSelectionContainer, or field_parameter_state needs to be set up for them. 

**Code for reproduction**

This uses the output_00080 ramses cosmological data available online. 

```python
import yt
import numpy as np

num = 80
Look = [1.,1.,0]
Up = [0.,1.,1.]

c = np.array([0.5,0.5,0.5])
rad = 0.2
left  = c - rad*1.05
right = c + rad*1.05
bb = [left,right]

fn = "./output_{0:05d}/info_{0:05d}.txt"
ds = yt.load(fn.format(num),bbox=bb)

region = ds.region(c,left,right)
d30 = region.cut_region(['obj["density"] > 1e-30'])

# This works
p1 = yt.OffAxisProjectionPlot(ds,Look,"density",weight_field='density',center=c,width=2*rad,data_source=region,north_vector=Up)
p1.save("OAProjDens_Region_{0:03d}.png".format(num))

# This doesn't
p1 = yt.OffAxisProjectionPlot(ds,Look,"density",weight_field='density',center=c,width=2*rad,data_source=d30,north_vector=Up)
p1.save("OAProjDens_D30_{0:03d}.png".format(num))
```

**Actual outcome**

<!--The output produced by the above code, which may be a screenshot, console
output, etc.-->

```
yt : [INFO     ] 2018-02-20 16:41:20,597 Parameters: current_time              = 1.11921656406
yt : [INFO     ] 2018-02-20 16:41:20,597 Parameters: domain_dimensions         = [64 64 64]
yt : [INFO     ] 2018-02-20 16:41:20,597 Parameters: domain_left_edge          = [ 0.  0.  0.]
yt : [INFO     ] 2018-02-20 16:41:20,598 Parameters: domain_right_edge         = [ 1.  1.  1.]
yt : [INFO     ] 2018-02-20 16:41:20,598 Parameters: cosmological_simulation   = 1
yt : [INFO     ] 2018-02-20 16:41:20,598 Parameters: current_redshift          = 0.142557286322
yt : [INFO     ] 2018-02-20 16:41:20,598 Parameters: omega_lambda              = 0.723999977112
yt : [INFO     ] 2018-02-20 16:41:20,598 Parameters: omega_matter              = 0.276000022888
yt : [INFO     ] 2018-02-20 16:41:20,598 Parameters: hubble_constant           = 0.703000030518
yt : [WARNING  ] 2018-02-20 16:41:20,612 Detected 2 extra particle fields assuming kind `double`. Consider using the `extra_particle_fields` keyword argument if you have unexpected behavior.
yt : [INFO     ] 2018-02-20 16:41:22,661 xlim = -0.200000 0.200000
yt : [INFO     ] 2018-02-20 16:41:22,661 ylim = -0.200000 0.200000
yt : [INFO     ] 2018-02-20 16:41:22,661 zlim = -0.500000 0.500000
yt : [INFO     ] 2018-02-20 16:41:22,670 Making a fixed resolution buffer of (('gas', 'density')) 800 by 800
/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/units/yt_array.py:1130: RuntimeWarning: invalid value encountered in divide
  np.divide(self, oth, out=self)
yt : [INFO     ] 2018-02-20 16:41:31,633 Saving plot OAProjDens_Region_080.png
yt : [INFO     ] 2018-02-20 16:41:32,467 xlim = -0.200000 0.200000
yt : [INFO     ] 2018-02-20 16:41:32,467 ylim = -0.200000 0.200000
yt : [INFO     ] 2018-02-20 16:41:32,467 zlim = -0.500000 0.500000
yt : [INFO     ] 2018-02-20 16:41:32,468 Making a fixed resolution buffer of (('gas', 'density')) 800 by 800
Traceback (most recent call last):
  File "Bug_OAProj_Container.py", line 25, in <module>
    p1 = yt.OffAxisProjectionPlot(ds,Look,"density",weight_field='density',center=c,width=2*rad,data_source=d30,north_vector=Up)
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/plot_window.py", line 1727, in __init__
    fontsize=fontsize)
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/plot_window.py", line 660, in __init__
    PlotWindow.__init__(self, *args, **kwargs)
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/plot_window.py", line 219, in __init__
    self._setup_plots()
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/plot_window.py", line 748, in _setup_plots
    self._recreate_frb()
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/plot_window.py", line 1733, in _recreate_frb
    super(OffAxisProjectionPlot, self)._recreate_frb()
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/plot_window.py", line 272, in _recreate_frb
    self._frb._get_data_source_fields()
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/fixed_resolution.py", line 155, in _get_data_source_fields
    self[f]
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/fixed_resolution.py", line 543, in __getitem__
    method=dd.method)
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/visualization/volume_rendering/off_axis_projection.py", line 189, in off_axis_projection
    for i, (grid, mask) in enumerate(data_source.blocks):
  File "/mnt/blackwhale/home/mrichard/soft/yt/yt_cphyc/yt/data_objects/selection_data_containers.py", line 836, in blocks
    with obj._field_parameter_state(self.field_parameters):
AttributeError: 'OctreeSubsetBlockSlicePosition' object has no attribute '_field_parameter_state'
```

**Expected outcome**

There should be two output png files generated. Currently only one is generated. The second would cut out all material more diffuse than 1e-30 g/cm^3

**Version Information**
<!--Please specify your platform and versions of the relevant libraries you are
using:-->
  * Operating System: CentOS
  * Python Version: 2.7.13
  * yt version: 3.5.dev0
  * Other Libraries (if applicable): 

yt was installed with conda from source. 




Discussion:
This is happening because `OctreeBlockSlicePosition` doesn't inherit from `YTSelectionContainer` so it doesn't implement the full data selection API. The fix is either to make `OctreeBlockSlicePosition` a first class data object (I have no idea offhand why it isn't, `AMRGridPatch`, which plays the same role for AMR data, is a data object) or to add a `field_parameters` dict as an attribute to `OctreeBlockSlicePosition` and add a `field_parameter_state` context manager as well.

Resolving patch:
diff --git a/yt/data_objects/octree_subset.py b/yt/data_objects/octree_subset.py
--- a/yt/data_objects/octree_subset.py
+++ b/yt/data_objects/octree_subset.py
@@ -14,6 +14,7 @@
 # The full license is in the file COPYING.txt, distributed with this software.
 #-----------------------------------------------------------------------------
 
+from contextlib import contextmanager
 import numpy as np
 
 from yt.data_objects.data_containers import \
@@ -479,6 +480,10 @@ def clear_data(self):
     def get_vertex_centered_data(self, *args, **kwargs):
         raise NotImplementedError
 
+    @contextmanager
+    def _field_parameter_state(self, field_parameters):
+        yield self.block_slice.octree_subset._field_parameter_state(
+                field_parameters)
 
 class OctreeSubsetBlockSlice(object):
     def __init__(self, octree_subset):


Test patch:
diff --git a/yt/visualization/tests/test_offaxisprojection.py b/yt/visualization/tests/test_offaxisprojection.py
--- a/yt/visualization/tests/test_offaxisprojection.py
+++ b/yt/visualization/tests/test_offaxisprojection.py
@@ -19,9 +19,14 @@
 
 from yt.visualization.image_writer import write_projection
 from yt.testing import \
-    fake_random_ds, expand_keywords, assert_fname
+    assert_equal, \
+    assert_fname, \
+    expand_keywords, \
+    fake_octree_ds, \
+    fake_random_ds
 from yt.visualization.volume_rendering.api import off_axis_projection
-
+from yt.visualization.api import OffAxisProjectionPlot, \
+    OffAxisSlicePlot
 
 class TestOffAxisProjection(unittest.TestCase):
     @classmethod
@@ -88,3 +93,17 @@ def test_oap(self):
 
         write_projection(image, "test_4.eps", xlabel="x-axis", ylabel="y-axis")
         assert_fname("test_4.eps")
+
+def test_field_cut_off_axis_octree():
+    ds = fake_octree_ds() 
+    cut = ds.all_data().cut_region('obj["density"]>0.5') 
+    p1 = OffAxisProjectionPlot(ds, [1, 0, 0], 'density')
+    p2 = OffAxisProjectionPlot(ds, [1, 0, 0], 'density', data_source=cut)
+    assert_equal(p2.frb["density"].min() == 0.0, True) # Lots of zeros
+    assert_equal((p1.frb["density"] == p2.frb["density"]).all(), False)
+    p3 = OffAxisSlicePlot(ds, [1, 0, 0], 'density')
+    p4 = OffAxisSlicePlot(ds, [1, 0, 0], 'density', data_source=cut)
+    assert_equal((p3.frb["density"] == p4.frb["density"]).all(), False)
+    p4rho = p4.frb["density"]
+    assert_equal(p4rho.min() == 0.0, True) # Lots of zeros
+    assert_equal(p4rho[p4rho > 0.0].min() >= 0.5, True)