Skip to content

Commit

Permalink
68 path optional plot forecast (#71)
Browse files Browse the repository at this point in the history
* Make path an optional input variable in plot_forecast() #68

* Fix tutorial to reflect changes in plot_forecast() #68

* Addressing code review comments #68

* Fix bug with respect to the case where path is empty and not None. Add relevant tests. #68

* Use return 0 to indicate successful execution and return 1 for the opposite. #68
  • Loading branch information
slenas authored and bezes committed Oct 16, 2018
1 parent abf4620 commit 2856f6b
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 25 deletions.
5 changes: 2 additions & 3 deletions anticipy/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,8 @@ def run_forecast_app(path_in, path_out=None, forecast_years=2.0,
df_metadata.to_csv(path_metadata, index=False)

try:
forecast_plot.plot_forecast(
df_result, path_plot, output=output_format, width=1920,
height=1080)
forecast_plot.plot_forecast(df_result, output_format, path_plot,
width=1920, height=1080)
except AssertionError:
logger.info("Couldn't generate plot - The required plotting library "
"is not installed")
Expand Down
23 changes: 16 additions & 7 deletions anticipy/forecast_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,8 @@ def _plotly_forecast_create(df_fcast, subplots, sources, nrows, ncols,
return fig


def plot_forecast(df_fcast, path, output='html', width=None,
height=None, title=None, dpi=70, show_legend=True,
auto_open=False):
def plot_forecast(df_fcast, output, path=None, width=None, height=None,
title=None, dpi=70, show_legend=True, auto_open=False):
"""
Generates matplotlib or plotly plot and saves it respectively as png or
html
Expand All @@ -334,12 +333,13 @@ def plot_forecast(df_fcast, path, output='html', width=None,
| - date (timestamp)
| - model (str) : ID for the forecast model
| - y (float) : Value of the time series in that sample
| - is_actuals (bool) : True for actuals samples, False for forecasted samples # noqa
| - is_actuals (bool) : True for actuals samples, False for
| forecasted samples # noqa
:type df_fcast: pandas.DataFrame
:param output: Indicates the output type (html=Default, png or jupyter)
:type output: basestring
:param path: File path for output
:type path: basestring
:param output: ...
:type output: ...
:param width: Image width, in pixels
:type width: int
:param height: Image height, in pixels
Expand All @@ -353,10 +353,17 @@ def plot_forecast(df_fcast, path, output='html', width=None,
:param auto_open: Indicates whether the output will be displayed
automatically
:type auto_open: bool
:return: Success or failure code.
:rtype: int
"""

assert isinstance(df_fcast, pd.DataFrame)

if not path and (output == 'html' or output == 'png'):
logger.error('No export path provided.')
return 1

if 'source' in df_fcast.columns:
subplots = True
sources = df_fcast.loc[df_fcast['is_actuals'], 'source'].unique()
Expand All @@ -375,6 +382,7 @@ def plot_forecast(df_fcast, path, output='html', width=None,
fig = _matplotlib_forecast_create(df_fcast, subplots, sources,
nrows, ncols, width, height,
title, dpi, show_legend)

path = '{}.png'.format(path)
dirname, fname = os.path.split(path)
if not os.path.exists(dirname):
Expand Down Expand Up @@ -412,5 +420,6 @@ def plot_forecast(df_fcast, path, output='html', width=None,
else:
logger.error('Wrong exporting format provided. Either png, html or '
'jupyter formats are supported at the moment.')
return 0
return 1

return 0
13 changes: 7 additions & 6 deletions docs/source/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,20 @@ The tool automatically selects the best model from a list of defaults - in this
users can instead provide their preferred model or lists of candidate models, as explained in :ref:`models`.

You can plot the forecast output using the functions in :py:mod:`forecast_plot`.
:py:func:`anticipy.forecast_plot.plot_forecast_save` saves the plot as a file. If you use
nsa.forecast in a Jupyter notebook, :py:func:`anticipy.forecast_plot.plot_forecast` shows the plot as the output of
a notebook cell. The plot looks as follows:
:py:func:`anticipy.forecast_plot.plot_forecast` saves the plot as a file or
exports it to a jupyter notebook. The plot looks as follows:

.. image:: resources/tutorial-forecast1.png

The code to generate the plot is::

path_tutorial_plot = 'plot-tutorial.png'
path_tutorial_plot = 'plot-tutorial'
# Save plot as a file
forecast_plot.plot_forecast_save(df_forecast, path_tutorial_plot,width=350, height=240, title='Tutorial Forecast')
forecast_plot.plot_forecast(df_forecast, output='html',
path=path_tutorial_plot, width=350, height=240, title='Tutorial Forecast')
# Show plot in a jupyter notebook
forecast_plot.plot_forecast(df_forecast, width=350, height=240, title='Tutorial Forecast')
forecast_plot.plot_forecast(df_forecast, output='jupyter', width=350,
height=240, title='Tutorial Forecast')



Expand Down
43 changes: 34 additions & 9 deletions tests/test_forecast_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,67 +96,92 @@ def test_plot_forecast_png(self):
if not forecast_plot._matplotlib_imported:
self.skipTest('Test skipped as Matplotlib is not installed...')
path = get_file_path(base_folder, 'test_mpl')
forecast_plot.plot_forecast(df_forecast, path, 'png', 900, 600,
forecast_plot.plot_forecast(df_forecast, 'png', path, 900, 600,
'Test Plot', show_legend=False,
auto_open=False)
self.assertTrue(os.path.isfile('{}.png'.format(path)))

path = get_file_path(base_folder, 'test_facet_mpl')
forecast_plot.plot_forecast(df_forecast_facet, path, 'png', 1200, 900,
forecast_plot.plot_forecast(df_forecast_facet, 'png', path, 1200, 900,
'Test Plot', show_legend=True,
auto_open=False)
self.assertTrue(os.path.isfile('{}.png'.format(path)))

# Repeat test with prediction intervals
path = get_file_path(base_folder, 'test_pi_mpl')
forecast_plot.plot_forecast(df_forecast_pi, path, 'png', 900, 600,
forecast_plot.plot_forecast(df_forecast_pi, 'png', path, 900, 600,
'Test Plot', show_legend=True,
auto_open=False)
self.assertTrue(os.path.isfile('{}.png'.format(path)))

path = get_file_path(base_folder, 'test_pi_facet_mpl')
forecast_plot.plot_forecast(df_forecast_pi_facet, path, 'png', 1200,
forecast_plot.plot_forecast(df_forecast_pi_facet, 'png', path, 1200,
900, 'Test Plot', show_legend=True,
auto_open=False)
self.assertTrue(os.path.isfile('{}.png'.format(path)))

# Test the case where a 'None' or an empty path is provided
self.assertTrue(forecast_plot.plot_forecast(df_forecast_pi_facet,
'png', None, 1200, 900,
'Test Plot',
show_legend=True,
auto_open=False))

self.assertTrue(forecast_plot.plot_forecast(df_forecast_pi_facet,
'png', '', 1200, 900,
'Test Plot',
show_legend=True,
auto_open=False))

def test_plot_forecast_html(self):
if not forecast_plot._plotly_imported:
self.skipTest('Test skipped as Plotly is not installed...')

path = get_file_path(base_folder, 'test_plotly')
forecast_plot.plot_forecast(df_forecast, path, 'html', 900, 600,
forecast_plot.plot_forecast(df_forecast, 'html', path, 900, 600,
'Test Plot', show_legend=False,
auto_open=False)
self.assertTrue(os.path.isfile('{}.html'.format(path)))

path = get_file_path(base_folder, 'test_facet_plotly')
forecast_plot.plot_forecast(df_forecast_facet, path, 'html', 1900,
forecast_plot.plot_forecast(df_forecast_facet, 'html', path, 1900,
1200, 'Test Plot', show_legend=False,
auto_open=False)
self.assertTrue(os.path.isfile('{}.html'.format(path)))

# Repeat test with prediction intervals
path = get_file_path(base_folder, 'test_pi_plotly')
forecast_plot.plot_forecast(df_forecast_pi, path, 'html', 900, 600,
forecast_plot.plot_forecast(df_forecast_pi, 'html', path, 900, 600,
'Test Plot', show_legend=False,
auto_open=False)
self.assertTrue(os.path.isfile('{}.html'.format(path)))

path = get_file_path(base_folder, 'test_pi_facet_plotly')
forecast_plot.plot_forecast(df_forecast_pi_facet, path, 'html', 1900,
forecast_plot.plot_forecast(df_forecast_pi_facet, 'html', path, 1900,
1200, 'Test Plot', show_legend=False,
auto_open=False)
self.assertTrue(os.path.isfile('{}.html'.format(path)))

# Test the case where a 'None' or an empty path is provided
self.assertTrue(forecast_plot.plot_forecast(df_forecast_pi_facet,
'html', None, 1900, 1200,
'Test Plot',
show_legend=False,
auto_open=False))

self.assertTrue(forecast_plot.plot_forecast(df_forecast_pi_facet,
'html', '', 1900, 1200,
'Test Plot',
show_legend=False,
auto_open=False))

def test_plot_forecast_jupyter(self):
if (not forecast_plot._plotly_imported) or \
(not forecast_plot._ipython_imported):
self.skipTest('Test skipped as either plotly or IPython is '
'not installed...')

forecast_plot.plot_forecast(df_forecast_pi_facet,
path=None,
output='jupyter',
width=1900,
height=1200,
Expand Down

0 comments on commit 2856f6b

Please sign in to comment.