Repository: mlflow/mlflow

Issue:
ImportError: No module named matplotlib.pyplot in examples/sklearn_elasticnet_diabetes/train_diabetes.py in mlflow docker image
### System information
- **Have I written custom code (as opposed to using a stock example script provided in MLflow)**:
examples/sklearn_elasticnet_diabetes/train_diabetes.py
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: MacOS 10.14.2
- **MLflow installed from (source or binary)**: MLflow Docker image
- **MLflow version (run ``mlflow --version``)**: mlflow, version 0.8.2.dev0
- **Python version**: 2.7.15
- **npm version (if running the dev UI):
- **Exact command to reproduce**:
```
docker run -it --rm mlflow /bin/bash
cd examples/sklearn_elasticnet_diabetes
python train_diabetes.py
```

### Describe the problem
When running this example, received ImportError message indicating missing matplotlib.pyplot


### Source code / logs
```
afc1d47c9ac2:python -u /opt/project/examples/sklearn_elasticnet_diabetes/train_diabetes.py
Traceback (most recent call last):
  File "/opt/project/examples/sklearn_elasticnet_diabetes/train_diabetes.py", line 26, in <module>
    import matplotlib.pyplot as plt
ImportError: No module named matplotlib.pyplot

Process finished with exit code 1
```

### Root Cause Analysis
matplotlib package not part of the Dockerfile to build the image.  Need to add matplotlib to the package requirements file (test-requirements.txt).  

Initial attempt at adding matplotlib to test-requirements.txt causes the docker image build to fail because install of dependent package (subprocess32)  fails.  Currently researching this.  See attached log file for details: [mlflow_dockerfile_build_failure.txt](https://github.com/mlflow/mlflow/files/2780626/mlflow_dockerfile_build_failure.txt)


Discussion:

Resolving patch:
diff --git a/examples/sklearn_elasticnet_diabetes/train_diabetes.py b/examples/sklearn_elasticnet_diabetes/linux/train_diabetes.py
similarity index 98%
rename from examples/sklearn_elasticnet_diabetes/train_diabetes.py
rename to examples/sklearn_elasticnet_diabetes/linux/train_diabetes.py
--- a/examples/sklearn_elasticnet_diabetes/train_diabetes.py
+++ b/examples/sklearn_elasticnet_diabetes/linux/train_diabetes.py
@@ -122,4 +122,4 @@ def eval_metrics(actual, pred):
     plt.close(fig)
 
     # Log artifacts (output files)
-    mlflow.log_artifact("ElasticNet-paths.png")
\ No newline at end of file
+    mlflow.log_artifact("ElasticNet-paths.png")
diff --git a/examples/sklearn_elasticnet_diabetes/osx/train_diabetes.py b/examples/sklearn_elasticnet_diabetes/osx/train_diabetes.py
new file mode 100644
--- /dev/null
+++ b/examples/sklearn_elasticnet_diabetes/osx/train_diabetes.py
@@ -0,0 +1,125 @@
+#
+# train_diabetes.py
+#
+#   MLflow model using ElasticNet (sklearn) and Plots ElasticNet Descent Paths
+#
+#   Uses the sklearn Diabetes dataset to predict diabetes progression using ElasticNet
+#       The predicted "progression" column is a quantitative measure of disease progression one year after baseline
+#       http://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html
+#   Combines the above with the Lasso Coordinate Descent Path Plot
+#       http://scikit-learn.org/stable/auto_examples/linear_model/plot_lasso_coordinate_descent_path.html
+#       Original author: Alexandre Gramfort <alexandre.gramfort@inria.fr>; License: BSD 3 clause
+#
+#  Usage:
+#    python train_diabetes.py 0.01 0.01
+#    python train_diabetes.py 0.01 0.75
+#    python train_diabetes.py 0.01 1.0
+#
+
+import os
+import warnings
+import sys
+
+import pandas as pd
+import numpy as np
+from itertools import cycle
+import matplotlib.pyplot as plt
+from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
+from sklearn.model_selection import train_test_split
+from sklearn.linear_model import ElasticNet
+from sklearn.linear_model import lasso_path, enet_path
+from sklearn import datasets
+
+# Load Diabetes datasets
+diabetes = datasets.load_diabetes()
+X = diabetes.data
+y = diabetes.target
+
+# Create pandas DataFrame for sklearn ElasticNet linear_model
+Y = np.array([y]).transpose()
+d = np.concatenate((X, Y), axis=1)
+cols = diabetes.feature_names + ['progression']
+data = pd.DataFrame(d, columns=cols)
+
+
+# Import mlflow
+import mlflow
+import mlflow.sklearn
+
+
+# Evaluate metrics
+def eval_metrics(actual, pred):
+    rmse = np.sqrt(mean_squared_error(actual, pred))
+    mae = mean_absolute_error(actual, pred)
+    r2 = r2_score(actual, pred)
+    return rmse, mae, r2
+
+
+
+if __name__ == "__main__":
+    warnings.filterwarnings("ignore")
+    np.random.seed(40)
+
+    # Split the data into training and test sets. (0.75, 0.25) split.
+    train, test = train_test_split(data)
+
+    # The predicted column is "progression" which is a quantitative measure of disease progression one year after baseline
+    train_x = train.drop(["progression"], axis=1)
+    test_x = test.drop(["progression"], axis=1)
+    train_y = train[["progression"]]
+    test_y = test[["progression"]]
+
+    alpha = float(sys.argv[1]) if len(sys.argv) > 1 else 0.05
+    l1_ratio = float(sys.argv[2]) if len(sys.argv) > 2 else 0.05
+
+    # Run ElasticNet
+    lr = ElasticNet(alpha=alpha, l1_ratio=l1_ratio, random_state=42)
+    lr.fit(train_x, train_y)
+    predicted_qualities = lr.predict(test_x)
+    (rmse, mae, r2) = eval_metrics(test_y, predicted_qualities)
+
+    # Print out ElasticNet model metrics
+    print("Elasticnet model (alpha=%f, l1_ratio=%f):" % (alpha, l1_ratio))
+    print("  RMSE: %s" % rmse)
+    print("  MAE: %s" % mae)
+    print("  R2: %s" % r2)
+
+    # Log mlflow attributes for mlflow UI
+    mlflow.log_param("alpha", alpha)
+    mlflow.log_param("l1_ratio", l1_ratio)
+    mlflow.log_metric("rmse", rmse)
+    mlflow.log_metric("r2", r2)
+    mlflow.log_metric("mae", mae)
+    mlflow.sklearn.log_model(lr, "model")
+
+
+    # Compute paths
+    eps = 5e-3  # the smaller it is the longer is the path
+
+    print("Computing regularization path using the elastic net.")
+    alphas_enet, coefs_enet, _ = enet_path(X, y, eps=eps, l1_ratio=l1_ratio, fit_intercept=False)
+
+    # Display results
+    fig = plt.figure(1)
+    ax = plt.gca()
+
+    colors = cycle(['b', 'r', 'g', 'c', 'k'])
+    neg_log_alphas_enet = -np.log10(alphas_enet)
+    for coef_e, c in zip(coefs_enet, colors):
+        l2 = plt.plot(neg_log_alphas_enet, coef_e, linestyle='--', c=c)
+
+    plt.xlabel('-Log(alpha)')
+    plt.ylabel('coefficients')
+    title = 'ElasticNet Path by alpha for l1_ratio = ' + str(l1_ratio)
+    plt.title(title)
+    plt.axis('tight')
+
+
+    # Save figures
+    fig.savefig("ElasticNet-paths.png")
+
+    # Close plot
+    plt.close(fig)
+
+    # Log artifacts (output files)
+    mlflow.log_artifact("ElasticNet-paths.png")


Test patch: