Repository: wright-group/WrightTools

Issue:
more descriptive response when converting axes
Would be nice to have source and destination units printed during conversion. This is especially useful when the conversion happens inside of some method.

Current behavior: `axis w1 converted`
Desired behavior: `axis w1 converted from wn to eV`


Discussion:
https://github.com/wright-group/WrightTools/blob/bd294e878ce2fedb2a97d312530f6c29c9ab21e2/WrightTools/data/_data.py#L433
Note, it is preferred to use `.format` rather than just passing multiple strings to print as is done here

Documentation [here](https://docs.python.org/3.6/library/stdtypes.html#str.format)
we should also update the docs...
https://github.com/wright-group/WrightTools/blob/b98adc7f517508ffb6d20c761efdb713bec42486/WrightTools/data/_data.py#L440

Also update the quickstart documentation to match:

https://github.com/wright-group/WrightTools/blob/b6c36c6c2196d957a465f01a0a69c851094010d9/docs/quickstart.rst#L89-L92

Resolving patch:
diff --git a/WrightTools/data/_data.py b/WrightTools/data/_data.py
--- a/WrightTools/data/_data.py
+++ b/WrightTools/data/_data.py
@@ -62,7 +62,9 @@ def __init__(self, *args, **kwargs):
 
     def __repr__(self):
         return "<WrightTools.Data '{0}' {1} at {2}>".format(
-            self.natural_name, str(self.axis_names), "::".join([self.filepath, self.name])
+            self.natural_name,
+            str(self.axis_names),
+            "::".join([self.filepath, self.name]),
         )
 
     @property
@@ -220,7 +222,9 @@ def print_leaves(prefix, lis, vline=True):
         else:
             # axes
             s = "axes: "
-            s += ", ".join(["{0} ({1})".format(a.expression, a.units) for a in self.axes])
+            s += ", ".join(
+                ["{0} ({1})".format(a.expression, a.units) for a in self.axes]
+            )
             print(prefix + "├── " + s)
             # channels
             s = "channels: "
@@ -338,8 +342,12 @@ def chop(self, *args, at={}, parent=None, verbose=True):
                 kwargs["signed"] = c.signed
                 kwargs.update(c.attrs)
                 data.create_channel(**kwargs)
-            new_axes = [a.expression for a in kept_axes if a.expression not in at.keys()]
-            new_axis_units = [a.units for a in kept_axes if a.expression not in at.keys()]
+            new_axes = [
+                a.expression for a in kept_axes if a.expression not in at.keys()
+            ]
+            new_axis_units = [
+                a.units for a in kept_axes if a.expression not in at.keys()
+            ]
             data.transform(*new_axes)
             for j, units in enumerate(new_axis_units):
                 data.axes[j].convert(units)
@@ -390,7 +398,9 @@ def collapse(self, axis, method="integrate"):
         # collapse --------------------------------------------------------------------------------
         for method, channel in zip(methods, self.channels):
             if method in ["int", "integrate"]:
-                channel[:] = np.trapz(y=channel[:], x=self._axes[axis_index][:], axis=axis_index)
+                channel[:] = np.trapz(
+                    y=channel[:], x=self._axes[axis_index][:], axis=axis_index
+                )
             elif method == "sum":
                 channel[:] = np.nansum(channel[:], axis=axis_index)
             elif method in ["max", "maximum"]:
@@ -427,16 +437,25 @@ def convert(self, destination_units, *, convert_variables=False, verbose=True):
         # apply to all compatible axes
         for axis in self.axes:
             if axis.units_kind == units_kind:
+                orig = axis.units
                 axis.convert(destination_units, convert_variables=convert_variables)
                 if verbose:
-                    print("axis", axis.expression, "converted")
+                    print(
+                        "axis {} converted from {} to {}".format(
+                            axis.expression, orig, destination_units
+                        )
+                    )
         if convert_variables:
             for var in self.variables:
                 if wt_units.kind(var.units) == units_kind:
+                    orig = var.units
                     var.convert(destination_units)
-
                     if verbose:
-                        print("variable", var.natural_name, "converted")
+                        print(
+                            "variable {} converted from {} to {}".format(
+                                var.natural_name, orig, destination_units
+                            )
+                        )
         self._on_axes_updated()
 
     def create_channel(self, name, values=None, shape=None, units=None, **kwargs):
@@ -478,7 +497,9 @@ def create_channel(self, name, values=None, shape=None, units=None, **kwargs):
         dataset_id = self.require_dataset(name=name, chunks=True, **require_kwargs).id
         channel = Channel(self, dataset_id, units=units, **kwargs)
         # finish
-        self.attrs["channel_names"] = np.append(self.attrs["channel_names"], name.encode())
+        self.attrs["channel_names"] = np.append(
+            self.attrs["channel_names"], name.encode()
+        )
         return channel
 
     def create_variable(self, name, values=None, shape=None, units=None, **kwargs):
@@ -517,7 +538,9 @@ def create_variable(self, name, values=None, shape=None, units=None, **kwargs):
         variable = Variable(self, id, units=units, **kwargs)
         # finish
         self.variables.append(variable)
-        self.attrs["variable_names"] = np.append(self.attrs["variable_names"], name.encode())
+        self.attrs["variable_names"] = np.append(
+            self.attrs["variable_names"], name.encode()
+        )
         return variable
 
     def flush(self):
@@ -673,10 +696,19 @@ def level(self, channel, axis, npts, *, verbose=True):
         # finish
         channel._null = 0
         if verbose:
-            print("channel {0} leveled along axis {1}".format(channel.natural_name, axis))
+            print(
+                "channel {0} leveled along axis {1}".format(channel.natural_name, axis)
+            )
 
     def map_variable(
-        self, variable, points, input_units="same", *, name=None, parent=None, verbose=True
+        self,
+        variable,
+        points,
+        input_units="same",
+        *,
+        name=None,
+        parent=None,
+        verbose=True
     ):
         """Map points of an axis to new points using linear interpolation.
 
@@ -744,7 +776,9 @@ def map_variable(
         if self.ndim == 1:
 
             def interpolate(dataset, points):
-                function = scipy.interpolate.interp1d(variable[:], dataset[:], bounds_error=False)
+                function = scipy.interpolate.interp1d(
+                    variable[:], dataset[:], bounds_error=False
+                )
                 return function(points)
 
         else:
@@ -753,7 +787,9 @@ def interpolate(dataset, points):
 
             def interpolate(dataset, points):
                 values = dataset.full.flatten()
-                function = scipy.interpolate.LinearNDInterpolator(pts, values, rescale=True)
+                function = scipy.interpolate.LinearNDInterpolator(
+                    pts, values, rescale=True
+                )
                 new = function(out_pts)
                 new.shape = out.shape
                 return new
@@ -869,7 +905,9 @@ def offset(
         elif isinstance(offset_axis, str):
             offset_axis_index = self.axis_names.index(offset_axis)
         else:
-            raise TypeError("offset_axis: expected {int, str}, got %s" % type(offset_axis))
+            raise TypeError(
+                "offset_axis: expected {int, str}, got %s" % type(offset_axis)
+            )
         # new points
         new_points = [a[:] for a in self._axes]
         old_offset_axis_points = self._axes[offset_axis_index][:]
@@ -905,7 +943,9 @@ def offset(
             # grid data
             tup = tuple([arr[i] for i in range(len(arr) - 1)])
             # note that rescale is crucial in this operation
-            out = griddata(tup, arr[-1], new_xi, method=method, fill_value=np.nan, rescale=True)
+            out = griddata(
+                tup, arr[-1], new_xi, method=method, fill_value=np.nan, rescale=True
+            )
             channel[:] = out
         self._axes[offset_axis_index][:] = new_offset_axis_points
         # transpose out
@@ -1140,7 +1180,8 @@ def smooth(self, factors, channel=None, verbose=True):
                 transpose_order = range(len(values.shape))
                 # replace axis_index with zero
                 transpose_order = [
-                    len(values.shape) - 1 if i == axis_index else i for i in transpose_order
+                    len(values.shape) - 1 if i == axis_index else i
+                    for i in transpose_order
                 ]
                 transpose_order[len(values.shape) - 1] = axis_index
                 values = values.transpose(transpose_order)
@@ -1151,7 +1192,9 @@ def smooth(self, factors, channel=None, verbose=True):
                 for index in np.ndindex(values[..., 0].shape):
                     current_slice = values[index]
                     temp_slice = np.pad(current_slice, int(factor), mode=str("edge"))
-                    values[index] = np.convolve(temp_slice, w / w.sum(), mode=str("valid"))
+                    values[index] = np.convolve(
+                        temp_slice, w / w.sum(), mode=str("valid")
+                    )
                 # transpose out
                 values = values.transpose(transpose_order)
             # return array to channel object
@@ -1159,7 +1202,15 @@ def smooth(self, factors, channel=None, verbose=True):
         if verbose:
             print("smoothed data")
 
-    def split(self, axis, positions, units="same", direction="below", parent=None, verbose=True):
+    def split(
+        self,
+        axis,
+        positions,
+        units="same",
+        direction="below",
+        parent=None,
+        verbose=True,
+    ):
         """
         Split the data object along a given axis, in units.
 
@@ -1228,7 +1279,9 @@ def split(self, axis, positions, units="same", direction="below", parent=None, v
         if flip:
             indicies = [i - 1 for i in indicies]
         # process ---------------------------------------------------------------------------------
-        outs = wt_collection.Collection(name="split", parent=parent, edit_local=parent is not None)
+        outs = wt_collection.Collection(
+            name="split", parent=parent, edit_local=parent is not None
+        )
         start = 0
         stop = 0
         for i in range(len(indicies) + 1):
@@ -1258,7 +1311,9 @@ def split(self, axis, positions, units="same", direction="below", parent=None, v
                     attrs = dict(ch.attrs)
                     attrs.pop("name", None)
                     attrs.pop("units", None)
-                    new_data.create_channel(ch.natural_name, ch[:][slc], ch.units, **attrs)
+                    new_data.create_channel(
+                        ch.natural_name, ch[:][slc], ch.units, **attrs
+                    )
             else:
                 attrs = dict(self.attrs)
                 attrs.pop("name", None)
@@ -1291,7 +1346,11 @@ def split(self, axis, positions, units="same", direction="below", parent=None, v
                 if new_data is None:
                     print("  {0} : None".format(i))
                 elif len(new_data.shape) < len(self.shape):
-                    print("  {0} : {1} {2}(constant)".format(i, axis.natural_name, axis.units))
+                    print(
+                        "  {0} : {1} {2}(constant)".format(
+                            i, axis.natural_name, axis.units
+                        )
+                    )
                 else:
                     new_axis = new_data.axes[axis_index]
                     print(
@@ -1353,7 +1412,9 @@ def zoom(self, factor, order=1, verbose=True):
             axis[:] = scipy.ndimage.interpolation.zoom(axis[:], factor, order=order)
         # channels
         for channel in self.channels:
-            channel[:] = scipy.ndimage.interpolation.zoom(channel[:], factor, order=order)
+            channel[:] = scipy.ndimage.interpolation.zoom(
+                channel[:], factor, order=order
+            )
         # return
         if verbose:
             print("data zoomed to new shape:", self.shape)


Test patch: