Repository: yt-project/yt

Issue:
Profile computes the standard deviation instead of variance
Originally reported by: **Greg Bryan (Bitbucket: [gbryan](https://bitbucket.org/gbryan), GitHub: [gbryan](https://github.com/gbryan))**

----------------------------------------

Andrew Cunningham points out:

 In the following cookbook example:  [http://yt-project.org/doc/cookbook/simple_plots.html#profiles-with-variance](Link URL)

the variance along the profile is extracted:


```
#!python

variance = prof.variance['gas', 'velocity_magnitude'].value
```


But this is actually the standard deviation.

You can see how the `variance` array attached to the profile object is computed [https://bitbucket.org/yt_analysis/yt/src/09f0ef297d7068078a021fc8290d9e3519baf82d/yt/data_objects/profiles.py?at=yt&fileviewer=file-view-default#profiles.py-183](here)

----------------------------------------
- Bitbucket: https://bitbucket.org/yt_analysis/yt/issue/1306



Discussion:
*Original comment by* **Nathan Goldbaum (Bitbucket: [ngoldbaum](https://bitbucket.org/ngoldbaum), GitHub: [ngoldbaum](https://github.com/ngoldbaum))**:

----------------------------------------

Issue #1308 was marked as a duplicate of this issue.

*Original comment by* **Nathan Goldbaum (Bitbucket: [ngoldbaum](https://bitbucket.org/ngoldbaum), GitHub: [ngoldbaum](https://github.com/ngoldbaum))**:

----------------------------------------

We should probably replace the `variance` attribute with a new attribute named something like `standard_deviation` (or some other name we can bikeshed about). We'll also need to leave the old `variance` attribute behind, but make it so that accessing it raises a visible deprecation warning. Eventually, we can remove it.


Resolving patch:
diff --git a/doc/source/cookbook/profile_with_variance.py b/doc/source/cookbook/profile_with_standard_deviation.py
similarity index 83%
rename from doc/source/cookbook/profile_with_variance.py
rename to doc/source/cookbook/profile_with_standard_deviation.py
--- a/doc/source/cookbook/profile_with_variance.py
+++ b/doc/source/cookbook/profile_with_standard_deviation.py
@@ -19,14 +19,14 @@
                          weight_field='cell_mass')
 
 # Create arrays to plot.
-radius = prof.x.value
-mean = prof['gas', 'velocity_magnitude'].value
-variance = prof.variance['gas', 'velocity_magnitude'].value
+radius = prof.x
+mean = prof['gas', 'velocity_magnitude']
+std = prof.standard_deviation['gas', 'velocity_magnitude']
 
 # Plot the average velocity magnitude.
 plt.loglog(radius, mean, label='Mean')
 # Plot the variance of the velocity magnitude.
-plt.loglog(radius, variance, label='Standard Deviation')
+plt.loglog(radius, std, label='Standard Deviation')
 plt.xlabel('r [kpc]')
 plt.ylabel('v [cm/s]')
 plt.legend()
diff --git a/yt/analysis_modules/halo_analysis/halo_callbacks.py b/yt/analysis_modules/halo_analysis/halo_callbacks.py
--- a/yt/analysis_modules/halo_analysis/halo_callbacks.py
+++ b/yt/analysis_modules/halo_analysis/halo_callbacks.py
@@ -246,9 +246,9 @@ def profile(halo, bin_fields, profile_fields, n_bins=32, extrema=None, logs=None
         setattr(halo, storage, halo_store)
     halo_store.update(prof_store)
 
-    if hasattr(my_profile, "variance"):
-        variance_store = dict([(field, my_profile.variance[field]) \
-                           for field in my_profile.variance])
+    if my_profile.standard_deviation is not None:
+        variance_store = dict([(field, my_profile.standard_deviation[field]) \
+                               for field in my_profile.standard_deviation])
         variance_storage = "%s_variance" % storage
         if hasattr(halo, variance_storage):
             halo_variance_store = getattr(halo, variance_storage)
diff --git a/yt/data_objects/profiles.py b/yt/data_objects/profiles.py
--- a/yt/data_objects/profiles.py
+++ b/yt/data_objects/profiles.py
@@ -21,7 +21,8 @@
 from yt.funcs import \
     get_output_filename, \
     ensure_list, \
-    iterable
+    iterable, \
+    issue_deprecation_warning
 from yt.units.yt_array import \
     array_like_field, \
     YTQuantity
@@ -91,12 +92,22 @@ def __init__(self, data_source, weight_field = None):
         self.field_info = {}
         self.field_data = YTFieldData()
         if weight_field is not None:
-            self.variance = YTFieldData()
+            self.standard_deviation = YTFieldData()
             weight_field = self.data_source._determine_fields(weight_field)[0]
+        else:
+            self.standard_deviation = None
         self.weight_field = weight_field
         self.field_units = {}
         ParallelAnalysisInterface.__init__(self, comm=data_source.comm)
 
+    @property
+    def variance(self):
+        issue_deprecation_warning("""
+profile.variance incorrectly returns the profile standard deviation and has 
+been deprecated, use profile.standard_deviation instead."""
+        )
+        return self.standard_deviation
+
     def add_fields(self, fields):
         """Add fields to profile
 
@@ -153,13 +164,13 @@ def _finalize_storage(self, fields, temp_storage):
 
         all_val = np.zeros_like(temp_storage.values)
         all_mean = np.zeros_like(temp_storage.mvalues)
-        all_var = np.zeros_like(temp_storage.qvalues)
+        all_std = np.zeros_like(temp_storage.qvalues)
         all_weight = np.zeros_like(temp_storage.weight_values)
         all_used = np.zeros_like(temp_storage.used, dtype="bool")
 
-        # Combine the weighted mean and variance from each processor.
-        # For two samples with total weight, mean, and variance 
-        # given by w, m, and s, their combined mean and variance are:
+        # Combine the weighted mean and standard deviation from each processor.
+        # For two samples with total weight, mean, and standard deviation 
+        # given by w, m, and s, their combined mean and standard deviation are:
         # m12 = (m1 * w1 + m2 * w2) / (w1 + w2)
         # s12 = (m1 * (s1**2 + (m1 - m12)**2) + 
         #        m2 * (s2**2 + (m2 - m12)**2)) / (w1 + w2)
@@ -180,8 +191,8 @@ def _finalize_storage(self, fields, temp_storage):
                    all_store[p].weight_values)[all_store[p].used] / \
                    all_weight[all_store[p].used]
 
-                all_var[..., i][all_store[p].used] = \
-                  (old_weight * (all_var[..., i] +
+                all_std[..., i][all_store[p].used] = \
+                  (old_weight * (all_std[..., i] +
                                  (old_mean[..., i] - all_mean[..., i])**2) +
                    all_store[p].weight_values *
                    (all_store[p].qvalues[..., i] + 
@@ -189,7 +200,7 @@ def _finalize_storage(self, fields, temp_storage):
                      all_mean[..., i])**2))[all_store[p].used] / \
                     all_weight[all_store[p].used]
 
-        all_var = np.sqrt(all_var)
+        all_std = np.sqrt(all_std)
         del all_store
         self.used = all_used
         blank = ~all_used
@@ -206,10 +217,10 @@ def _finalize_storage(self, fields, temp_storage):
                 self.field_data[field] = \
                   array_like_field(self.data_source, 
                                    all_mean[...,i], field)
-                self.variance[field] = \
+                self.standard_deviation[field] = \
                   array_like_field(self.data_source,
-                                   all_var[...,i], field)
-                self.variance[field][blank] = 0.0
+                                   all_std[...,i], field)
+                self.standard_deviation[field][blank] = 0.0
             self.field_data[field][blank] = 0.0
             self.field_units[field] = self.field_data[field].units
             if isinstance(field, tuple):


Test patch: