Repository: wright-group/WrightTools

Issue:
Chopped does not propagate units in constants
See issue #459. It is a very related is to the issue I am seeing. I converted a dataset into wavenumbers, but when the data gets chopped during quick2D, it converts the units in constants back to their original units.


Discussion:
- To better diagnose this issue, can you post a minimal reproducible example? 
- Is this behavior present in only `quick2D` or is it present in `data.chop`? 
- When making an example can you try out `data.convert(*,convert_variables=True)` too?


Possibly helpful code blocks: 

https://github.com/wright-group/WrightTools/blob/413b4c2c96eae214c0efdf9280c564881a34d407/WrightTools/data/_data.py#L885

https://github.com/wright-group/WrightTools/blob/413b4c2c96eae214c0efdf9280c564881a34d407/WrightTools/data/_axis.py#L185
@darienmorrow kelson and I did look at this together. It is chop, the linked or corrected the behavior for axes, but not constants
Here is a much better example, and hopefully a better explanation, than what I had before. I did not fully understand what the issue was before, and it occurred while I was using quick2D. The issue is `wt.data.chop` though, and quick2D used this method, which is why I associated it with quick2D.

The issue is that when you chop a dataset that has had its units changed, the resulting chopped dataset has a new constant at where it was chopped. This constant is in the original units of the dataset, not the transformed units. This was relevant in quick2D, because it checks to see if any of the constants are the same units as an axis. When I first ran into this issue, that meant it was trying to compare 'mm' to 'nm' and was not recognizing that as a valid conversion.

## Example of chopping not propagating units

I have an example of what I am seeing below. I have print_trees of the data after each change, but I have removed the variables and channels from the data_tree, since I believe they are not relevant and they make the print_trees annoyingly long.
```
data.print_tree()
primary (C:\Users\Wright\AppData\Local\Temp\emw7muqy.wt5)
├── axes
│   ├── 0: twin1_points (nm) (13, 1, 1)
│   ├── 1: twin1_Delay_2 (mm) (13, 21, 51)
│   └── 2: mono-twin1 (nm) (13, 21, 51)
├── constants


data.convert('wn')
axis twin1_points converted from nm to wn
axis mono-twin1 converted from nm to wn

data.print_tree()
primary (C:\Users\Wright\AppData\Local\Temp\emw7muqy.wt5)
├── axes
│   ├── 0: twin1_points (wn) (13, 1, 1)
│   ├── 1: twin1_Delay_2 (mm) (13, 21, 51)
│   └── 2: mono-twin1 (wn) (13, 21, 51)
├── constants


data1 = data.chop('twin1_Delay_2','mono-twin1', at={'twin1_points':[data.twin1_points[0][0],'wn']})[0]
chopped data into 1 piece(s) in ('twin1_Delay_2', 'mono-twin1')

data1.print_tree()
chop0 (C:\Users\Wright\AppData\Local\Temp\7qhnzzse.wt5)
├── axes
│   ├── 0: twin1_Delay_2 (mm) (21, 51)
│   └── 1: mono-twin1 (wn) (21, 51)
├── constants
│   └── 0: twin1_points = 1300.0 nm
```
I have a new version of my example using @darienmorrow 's request of using `data.convert(*,convert_variables=True)`. I kept some of the variables in the print_tree this time because they were converted as well.

```
data.print_tree()
primary (C:\Users\Wright\AppData\Local\Temp\gsclje_b.wt5)
├── axes
│   ├── 0: twin1_points (nm) (13, 1, 1)
│   ├── 1: twin1_Delay_2 (mm) (13, 21, 51)
│   └── 2: mono-twin1 (nm) (13, 21, 51)
├── constants
├── variables
│   ├── 0: labtime (s) (13, 21, 51)
│   ├── 1: mono (nm) (13, 21, 51)
│   ├── 2: mono_destination (nm) (13, 21, 51)
│   ├── 3: twin1 (nm) (13, 21, 51)
│   ├── 4: twin1_destination (nm) (13, 21, 51)

data.convert('wn',convert_variables=True)
axis twin1_points converted from nm to wn
axis mono-twin1 converted from nm to wn
variable labtime converted from s to wn
variable mono converted from wn to wn
variable mono_destination converted from nm to wn
variable twin1 converted from wn to wn
variable twin1_destination converted from nm to wn
variable twin1_points converted from wn to wn
variable mono_points converted from nm to wn
variable hp converted from nm to wn
variable hp_destination converted from nm to wn
variable filter1 converted from nm to wn
variable filter1_destination converted from nm to wn
variable twin2 converted from nm to wn
variable twin2_destination converted from nm to wn
C:\Users\Wright\miniconda3\lib\site-packages\pint\quantity.py:1359: RuntimeWarning: divide by zero encountered in divide
  return self.__class__(other_magnitude / self._magnitude, 1 / self._units)

data.print_tree()
primary (C:\Users\Wright\AppData\Local\Temp\ezrzezwk.wt5)
├── axes
│   ├── 0: twin1_points (wn) (13, 1, 1)
│   ├── 1: twin1_Delay_2 (mm) (13, 21, 51)
│   └── 2: mono-twin1 (wn) (13, 21, 51)
├── constants
├── variables
│   ├── 0: labtime (wn) (13, 21, 51)
│   ├── 1: mono (wn) (13, 21, 51)
│   ├── 2: mono_destination (wn) (13, 21, 51)
│   ├── 3: twin1 (wn) (13, 21, 51)
│   ├── 4: twin1_destination (wn) (13, 21, 51)

data1 = data.chop('twin1_Delay_2','mono-twin1', at={'twin1_points':[data.twin1_points[0][0],'wn']})[0]
chopped data into 1 piece(s) in ('twin1_Delay_2', 'mono-twin1')

data1.print_tree()
chop0 (C:\Users\Wright\AppData\Local\Temp\manohxk5.wt5)
├── axes
│   ├── 0: twin1_Delay_2 (mm) (21, 51)
│   └── 1: mono-twin1 (wn) (21, 51)
├── constants
│   └── 0: twin1_points = 7692.307692307691 wn
├── variables
│   ├── 0: labtime (wn) (21, 51)
│   ├── 1: mono (wn) (21, 51)
│   ├── 2: mono_destination (wn) (21, 51)
│   ├── 3: twin1 (wn) (21, 51)
│   ├── 4: twin1_destination (wn) (21, 51)
```

This does propagate units correctly.
Is there a way for me to share a wt5 file on Github? I wanted to share the data I used for reproducibility, but it seems I can not do that here.
@kelsonoram I would suggest writing & sharing code to make a small data object that exhibits the same behavior.

Some past issues which relied on creation of small data objects:
https://github.com/wright-group/WrightTools/issues/1058
https://github.com/wright-group/WrightTools/issues/1010
https://github.com/wright-group/WrightTools/issues/960
https://github.com/wright-group/WrightTools/issues/881
@kelsonoram do you still think this is an issue?

To share data, you could provide a link to the data in question if it is hosted on e.g. google drive

Resolving patch:
diff --git a/WrightTools/data/_data.py b/WrightTools/data/_data.py
--- a/WrightTools/data/_data.py
+++ b/WrightTools/data/_data.py
@@ -596,6 +596,11 @@ def _from_slice(self, idx, name=None, parent=None) -> Data:
 
         for const in list(self.constant_expressions) + constants:
             out.create_constant(const, verbose=False)
+            if const in self.constant_expressions:
+                dest_units = self.constants[self.constant_expressions.index(const)].units
+            else:
+                dest_units = self.axes[self.axis_expressions.index(const)].units
+            out.constants[out.constant_expressions.index(const)].convert(dest_units)
         for j, units in enumerate(new_axis_units):
             out.axes[j].convert(units)
 


Test patch:
diff --git a/tests/data/chop.py b/tests/data/chop.py
--- a/tests/data/chop.py
+++ b/tests/data/chop.py
@@ -111,8 +111,10 @@ def test_3D_to_2D_units():
         assert d.w2.size == 11
         assert d.axis_expressions == ("wm", "w2")
         assert d.units == ("eV", "eV")
-    data.close()
+        w1 = d.constants[d.constant_names.index("w1")]
+        assert w1.units == "eV"
     chop.close()
+    data.close()
 
 
 def test_parent():