Repository: awslabs/gluonts

Issue:
Plotting compatibility with Quantile Forecasts
## Description
When attempting to plot prediction intervals for MQCNN (or other estimators that implement a QuantileForecast for their predictor), the plotting function does not plot intervals as its functionality is intended to. Instead, it plots a single line (which I understand to be the 0.5 quantile forecast).

## To Reproduce
(Please provide minimal example of code snippet that reproduces the error. For existing examples, please provide link.)

```python
import mxnet as mx
from mxnet import gluon
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import json
from gluonts.dataset.repository.datasets import get_dataset, dataset_recipes
from gluonts.dataset.util import to_pandas
from gluonts.evaluation.backtest import make_evaluation_predictions
from gluonts.trainer import Trainer
from gluonts.model.seq2seq import MQCNNEstimator

dataset = get_dataset("m4_hourly", regenerate=True)
estimator = MQCNNEstimator(freq=dataset.metadata.freq, 
                            prediction_length=dataset.metadata.prediction_length,
                            trainer=Trainer(epochs=2))
predictor = estimator.train(dataset.train)

forecast_it, ts_it = make_evaluation_predictions(
    dataset=dataset.test,  # test dataset
    predictor=predictor,  # predictor
    num_samples=100,  # number of sample paths we want for evaluation
)

forecasts = list(forecast_it)
tss = list(ts_it)

def plot_prob_forecasts(ts_entry, forecast_entry):
    plot_length = 150
    prediction_intervals = (50.0, 90.0)
    legend = ["observations", "median prediction"] + [f"{k}% prediction interval" for k in prediction_intervals][::-1]
    fig, ax = plt.subplots(1, 1, figsize=(10, 7))
    ts_entry[-plot_length:].plot(ax=ax)  # plot the time series
    forecast_entry.plot(prediction_intervals=prediction_intervals, color='g')
    plt.grid(which="both")
    plt.legend(legend, loc="upper left")
    plt.show()
    
plot_prob_forecasts(tss[0], forecasts[0])
```

## Error message or code output
(Paste the complete error message, including stack trace, or the undesired output that the above snippet produces.)

```
![image](https://user-images.githubusercontent.com/34934238/90322283-7ef2a480-df20-11ea-8350-f77dfcbb3f68.png)

```

## Environment
- Operating system: macOS Catalina 10.15.6
- Python version: 3.7.7
- GluonTS version: 0.4.3.dev241+g9b30bd7
- MXNet version: 1.6.0

(Add as much information about your environment as possible, e.g. dependencies versions.)



Discussion:
So the problem is that the `Forecast.plot` method is really tailored to the `SampleForecast` and `DistributionForecast` classes, for which the `quantile` method always returns something meaningful; in the case of `QuantileForecast`, `quantile` will give `nan` unless the model produced exactly the quantiles which are needed for plotting.

In my opinion it would make sense to implement `QuantileForecast.plot` ad-hoc and avoid falling back to `Forecast.plot`. This would not have the `prediction_intervals` option, and instead would plot one line per computed quantile: if the model was configured to produce those quantiles, then plotting the forecast should show those quantiles.

Resolving patch:
diff --git a/src/gluonts/model/forecast.py b/src/gluonts/model/forecast.py
--- a/src/gluonts/model/forecast.py
+++ b/src/gluonts/model/forecast.py
@@ -559,6 +559,22 @@ def __repr__(self):
             ]
         )
 
+    def plot(self, label=None, output_file=None, keys=None, *args, **kwargs):
+        import matplotlib.pyplot as plt
+
+        label_prefix = "" if label is None else label + "-"
+
+        if keys is None:
+            keys = self.forecast_keys
+
+        for k, v in zip(keys, self.forecast_array):
+            plt.plot(
+                self.index, v, label=f"{label_prefix}q{k}", *args, **kwargs,
+            )
+            plt.legend()
+        if output_file:
+            plt.savefig(output_file)
+
 
 class DistributionForecast(Forecast):
     """


Test patch: