Repository: arviz-devs/arviz

Issue:
Allow normalization in plot_parallel
It would be great if plot_parallel had a keyword arg `normalize` (or standardize), that centers and rescales the variables before plotting. That would make it easier to see things if some posteriors are much more tight than others:
![grafik](https://user-images.githubusercontent.com/1882397/48769279-83424d00-ecbb-11e8-8bf3-f1df15455cd0.png)


Discussion:
normalize --> `(x -np.mean(x))/np.std(x)`

minmax --> `(x-min(x))/(max(x)-min(x))`

uniform --> `ecdf(x)[x]`  <-- `inverse_ecdf_x(x)`
So we add a kwarg with those three options as string? What should it be called? Maybe `rescale`? We could use `normalize` if it is `True`.
`bayesplot` supports arbitrary transformations passed as a list of functions, I guess we could do the same. But calling it `transformation` could be confusing because we already have transformed variables, and we might want a log transform *and* a normalization in some cases.
Oh, and maybe instead of a `uniform` we could use `quantile` and also change the y-axis labels appropriately.

Resolving patch:
diff --git a/arviz/plots/parallelplot.py b/arviz/plots/parallelplot.py
--- a/arviz/plots/parallelplot.py
+++ b/arviz/plots/parallelplot.py
@@ -2,6 +2,7 @@
 import matplotlib.pyplot as plt
 import numpy as np
 
+from scipy.stats.mstats import rankdata
 from ..data import convert_to_dataset
 from .plot_utils import _scale_fig_size, xarray_to_ndarray, get_coords
 from ..utils import _var_names
@@ -18,6 +19,7 @@ def plot_parallel(
     colord="C1",
     shadend=0.025,
     ax=None,
+    norm_method=None,
 ):
     """
     Plot parallel coordinates plot showing posterior points with and without divergences.
@@ -50,10 +52,33 @@ def plot_parallel(
         Defaults to .025
     ax : axes
         Matplotlib axes.
+    norm_method : str
+        Method for normalizing the data. Methods include normal, minmax and rank.
+        Defaults to none.
 
     Returns
     -------
     ax : matplotlib axes
+
+    Examples
+    --------
+    Plot default parallel plot
+
+    .. plot::
+        :context: close-figs
+
+        >>> import arviz as az
+        >>> data = az.load_arviz_data('centered_eight')
+        >>> az.plot_parallel(data, var_names=["mu", "tau"])
+
+
+    Plot parallel plot with normalization
+
+    .. plot::
+        :context: close-figs
+
+        >>> az.plot_parallel(data, var_names=["mu", "tau"], norm_method='normal')
+
     """
     if coords is None:
         coords = {}
@@ -69,9 +94,23 @@ def plot_parallel(
     var_names, _posterior = xarray_to_ndarray(
         get_coords(posterior_data, coords), var_names=var_names, combined=True
     )
-
     if len(var_names) < 2:
         raise ValueError("This plot needs at least two variables")
+    if norm_method is not None:
+        if norm_method == "normal":
+            mean = np.mean(_posterior, axis=1)
+            standard_deviation = np.std(_posterior, axis=1)
+            for i in range(0, np.shape(mean)[0]):
+                _posterior[i, :] = (_posterior[i, :] - mean[i]) / standard_deviation[i]
+        elif norm_method == "minmax":
+            min_elem = np.min(_posterior, axis=1)
+            max_elem = np.max(_posterior, axis=1)
+            for i in range(0, np.shape(min_elem)[0]):
+                _posterior[i, :] = ((_posterior[i, :]) - min_elem[i]) / (max_elem[i] - min_elem[i])
+        elif norm_method == "rank":
+            _posterior = rankdata(_posterior, axis=1)
+        else:
+            raise ValueError("{} is not supported. Use normal, minmax or rank.".format(norm_method))
 
     figsize, _, _, xt_labelsize, _, _ = _scale_fig_size(figsize, textsize, 1, 1)
 


Test patch:
diff --git a/arviz/tests/test_plots.py b/arviz/tests/test_plots.py
--- a/arviz/tests/test_plots.py
+++ b/arviz/tests/test_plots.py
@@ -233,15 +233,17 @@ def test_plot_parallel_raises_valueerror(df_trace):  # pylint: disable=invalid-n
 
 
 @pytest.mark.parametrize("model_fit", ["pymc3_fit", "stan_fit"])
-def test_plot_parallel(models, model_fit):
+@pytest.mark.parametrize("norm_method", [None, "normal", "minmax", "rank"])
+def test_plot_parallel(models, model_fit, norm_method):
     obj = getattr(models, model_fit)
-    assert plot_parallel(obj, var_names=["mu", "tau"])
+    assert plot_parallel(obj, var_names=["mu", "tau"], norm_method=norm_method)
 
 
-def test_plot_parallel_exception(models):
+@pytest.mark.parametrize("var_names", [None, "mu", ["mu", "tau"]])
+def test_plot_parallel_exception(models, var_names):
     """Ensure that correct exception is raised when one variable is passed."""
     with pytest.raises(ValueError):
-        assert plot_parallel(models.pymc3_fit, var_names="mu")
+        assert plot_parallel(models.pymc3_fit, var_names=var_names, norm_method="foo")
 
 
 @pytest.mark.parametrize("model_fit", ["pymc3_fit", "stan_fit", "pyro_fit"])