6

I've been trying to get the "Filled-Area Animation in Python" example to work using plotly in offline mode in a Jupyter notebook. The example can be found here: https://plot.ly/python/filled-area-animation/

Since I'm in off-line mode, I create a local csv file containing dummy data to use as the data source, then read the csv using pandas dataframes:

# Add the following line
from plotly.offline import init_notebook_mode, iplot
.....
# Read csv instead of using get_data_yahoo
#appl = web.get_data_yahoo('AAPL', '2016-01-01', '2016-11-30')
appl = pd.read_csv("C:\\test.csv")
apple_data_matrix = appl.head(10)
.....
# Use offline version of iplot
#py.iplot(table, filename='apple_data_table')
iplot(table, filename='apple_data_table')

So far so good. The code to "Make the Grid" remains the same - except commenting out the last line which is on-line only:

def to_unix_time(dt):
    epoch =  datetime.utcfromtimestamp(0)
    return (dt - epoch).total_seconds() * 1000

appl_price = list(appl['Adj Close'])
my_columns = []
for k in range(len(appl.index) - 1):
    my_columns.append(Column(appl.index[:k + 1], 'x{}'.format(k + 1)))   
    my_columns.append(Column(appl_price[:k + 1], 'y{}'.format(k + 1)))
grid = Grid(my_columns)
#py.grid_ops.upload(grid, 'AAPL-daily-stock-price' + str(time.time()), auto_open=False)

The final section of the code ('Make the figure') is where I'm struggling. This is the code which draws the chart and animates it:

data=[dict(type='scatter',
           xsrc=grid.get_column_reference('x1'),
           ysrc= grid.get_column_reference('y1'),
           name='AAPL',
           mode='lines',
           line=dict(color= 'rgb(114, 186, 59)'),
           fill='tozeroy',
           fillcolor='rgba(114, 186, 59, 0.5)')]

axis=dict(ticklen=4,
          mirror=True,
          zeroline=False,
          showline=True,
          autorange=False,
          showgrid=False)

layout = dict(title='AAPL Daily Stock Price',
              font=dict(family='Balto'),
              showlegend=False,
              autosize=False,
              width=800,
              height=400,
              xaxis=dict(axis, **{'nticks':12, 'tickangle':-45,
                                  'range': [to_unix_time(datetime(2016, 1, 4)),
                                            to_unix_time(datetime(2016, 11, 30))]}),
              yaxis=dict(axis, **{'title': '$', 'range':[0,120]}),
              updatemenus=[dict(type='buttons',
                                showactive=False,
                                y=1,
                                x=1.1,
                                xanchor='right',
                                yanchor='top',
                                pad=dict(t=0, r=10),
                                buttons=[dict(label='Play',
                                              method='animate',
                                              args=[None, dict(frame=dict(duration=50, redraw=False), 
                                                               transition=dict(duration=0),
                                                               fromcurrent=True,
                                                               mode='immediate')])])])

frames=[{'data':[{'xsrc': grid.get_column_reference('x{}'.format(k + 1)),
                  'ysrc': grid.get_column_reference('y{}'.format(k + 1))}],
         'traces': [0]
        } for k in range(len(appl.index) - 1)]

fig=dict(data=data, layout=layout, frames=frames)
py.icreate_animations(fig, 'AAPL-stockprice' + str(time.time()))

py.icreate_animations (last line) is not available in off-line mode. I've tried replacing it with plotly.offline.iplot(fig) but get the following stack trace:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-17-c3918e48e33a> in <module>()
     46 fig=dict(data=data, layout=layout, frames=frames)
     47 #fig = go.Figure(data=data, layout=layout, frames=frames)
---> 48 plotly.offline.iplot(fig)
     49 #iplot.create_animations(fig, 'AAPL-stockprice' + str(time.time()))
     50 #py.icreate_animations(fig, 'AAPL-stockprice' + str(time.time()))

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\offline\offline.py in iplot(figure_or_data, show_link, link_text, validate, image, filename, image_width, image_height)
    340     )
    341 
--> 342     figure = tools.return_figure_from_figure_or_data(figure_or_data, validate)
    343 
    344     # Though it can add quite a bit to the display-bundle size, we include

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\tools.py in return_figure_from_figure_or_data(figure_or_data, validate_figure)
   1378 
   1379         try:
-> 1380             graph_objs.Figure(figure)
   1381         except exceptions.PlotlyError as err:
   1382             raise exceptions.PlotlyError("Invalid 'figure_or_data' argument. "

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in __init__(self, *args, **kwargs)
   1110 
   1111     def __init__(self, *args, **kwargs):
-> 1112         super(Figure, self).__init__(*args, **kwargs)
   1113         if 'data' not in self:
   1114             self.data = Data(_parent=self, _parent_key='data')

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in __init__(self, *args, **kwargs)
    375         d = {key: val for key, val in dict(*args, **kwargs).items()}
    376         for key, val in d.items():
--> 377             self.__setitem__(key, val, _raise=_raise)
    378 
    379     def __dir__(self):

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in __setitem__(self, key, value, _raise)
    430 
    431         if self._get_attribute_role(key) == 'object':
--> 432             value = self._value_to_graph_object(key, value, _raise=_raise)
    433             if not isinstance(value, (PlotlyDict, PlotlyList)):
    434                 return

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in _value_to_graph_object(self, key, value, _raise)
    541         # this can be `None` when `_raise == False`
    542         return GraphObjectFactory.create(key, value, _raise=_raise,
--> 543                                          _parent=self, _parent_key=key)
    544 
    545     def help(self, attribute=None, return_help=False):

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in create(object_name, *args, **kwargs)
    791         class_name = graph_reference.OBJECT_NAME_TO_CLASS_NAME.get(object_name)
    792         if class_name in ['Figure', 'Data', 'Frames']:
--> 793             return globals()[class_name](*args, **kwargs)
    794         else:
    795             kwargs['_name'] = object_name

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in __init__(self, *args, **kwargs)
    156 
    157         for index, value in enumerate(list(*args)):
--> 158             value = self._value_to_graph_object(index, value, _raise=_raise)
    159 
    160             if isinstance(value, PlotlyBase):

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in _value_to_graph_object(self, index, value, _raise)
   1010         return GraphObjectFactory.create(item, _raise=_raise,
   1011                                          _parent=self,
-> 1012                                          _parent_key=index, **value)
   1013 
   1014     def get_data(self, flatten=False):

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in create(object_name, *args, **kwargs)
    797                 return PlotlyList(*args, **kwargs)
    798             else:
--> 799                 return PlotlyDict(*args, **kwargs)
    800 
    801 

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in __init__(self, *args, **kwargs)
    375         d = {key: val for key, val in dict(*args, **kwargs).items()}
    376         for key, val in d.items():
--> 377             self.__setitem__(key, val, _raise=_raise)
    378 
    379     def __dir__(self):

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in __setitem__(self, key, value, _raise)
    400         if key.endswith('src'):
    401             if key in self._get_valid_attributes():
--> 402                 value = graph_objs_tools.assign_id_to_src(key, value)
    403                 return super(PlotlyDict, self).__setitem__(key, value)
    404 

C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\plotly\graph_objs\graph_objs_tools.py in assign_id_to_src(src_name, src_value)
    254     if src_id == '':
    255         err = exceptions.COLUMN_NOT_YET_UPLOADED_MESSAGE
--> 256         err.format(column_name=src_value.name, reference=src_name)
    257         raise exceptions.InputError(err)
    258     return src_id

AttributeError: 'str' object has no attribute 'name'

Can anyone help workout how to get the animation to work in offline mode.

Thanks in advance -- Simon

3 Answers 3

0

This issue is addressed in Plotly icreate_animations offline on Jupyter Notebook

According to that answer, the plotly.grid_objs Grid function is not supported offline. He transitions the code to use DataFrames instead, which avoids the issue.

Sign up to request clarification or add additional context in comments.

Comments

0

This is old, but if anybody is trying to figure it out, the only difference is the usage of from plotly.grid_objs import Grid, Column as data holders which can be easily replaced by a pandas.DataFrame or a dict.

By using a dict, replace the following code block:

my_columns = []
for k in range(len(appl.index) - 1):
    my_columns.append(Column(appl.index[:k + 1], 'x{}'.format(k + 1)))   
    my_columns.append(Column(appl_price[:k + 1], 'y{}'.format(k + 1)))
grid = Grid(my_columns)

with:

my_columns = {}
for k in range(len(appl.Date) - 1):
    my_columns['x{}'.format(k + 1)] = list(appl.Date)[:k + 1]
    my_columns['y{}'.format(k + 1)] = appl_price[:k + 1]

So whats happening? Plotly's Grid use the method get_column_reference later on which works exactly like a dict, it stores key value pairs that are used for the plot start as well as for its frames.

From there, replace all reference to the Grid to your created dict which is stored as my_columns from our change made above. Finally use iplot from the offline Python API instead of icreate_animations.

The second block of code:

data=[dict(type='scatter',
           x= my_columns['x1'],
           y= my_columns['y1'],
           name='AAPL',
           mode='lines',
           line=dict(color= 'rgb(114, 186, 59)'),
           fill='tozeroy',
           fillcolor='rgba(114, 186, 59, 0.5)')]

axis=dict(ticklen=4,
          mirror=True,
          zeroline=False,
          showline=True,
          autorange=False,
          showgrid=False)

layout = dict(title='AAPL Daily Stock Price',
              font=dict(family='Balto'),
              showlegend=False,
              autosize=False,
              xaxis=dict(axis, **{'nticks':12, 'tickangle':-45,
                                  'range': [to_unix_time(datetime(2015, 2, 17)),
                                            to_unix_time(datetime(2016, 11, 30))]}),
              yaxis=dict(axis, **{'title': '$', 'range':[0,170]}),
              updatemenus=[dict(type='buttons',
                                showactive=False,
                                y=1,
                                x=1.1,
                                xanchor='right',
                                yanchor='top',
                                pad=dict(t=0, r=10),
                                buttons=[dict(label='Play',
                                              method='animate',
                                              args=[None, dict(frame=dict(duration=50, redraw=True), 
                                                               transition=dict(duration=0),
                                                               fromcurrent=True,
                                                               mode='immediate')])])])

frames=[{'data':[{'x': my_columns['x{}'.format(k + 1)],
                  'y': my_columns['y{}'.format(k + 1)]}],
         'traces': [0]
        } for k in range(len(appl.Date) - 1)]


fig=dict(data=data, layout=layout, frames=frames)
iplot(fig,
      show_link=False, config=dict(displaylogo=False, modeBarButtonsToRemove=['sendDataToCloud']))

Comments

0

Gone are the days when you had to worry about using Plotly in an offline mode. In order to achieve the same chart that your source produces:

enter image description here

...you can now build on this excellent example from the Plotly community forum, add the following:

fig.data[1].fill = 'tozeroy'

... and get this:

enter image description here

Complete code:

import numpy as np
import pandas as pd
import plotly.graph_objects as go  #plotly 4.0.0rc1


df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
low = df['AAPL.Low'].tolist()
high = np.array(df['AAPL.High'])+20 # artificially added 20 to get the second graph above the first one

trace1 = go.Scatter(x=df.Date[:2],
                    y=low[:2],
                    mode='lines',
                    line=dict(width=1.5))

trace2 = go.Scatter(x = df.Date[:2],
                    y = high[:2],
                    mode='lines',
                    line=dict(width=1.5))

frames = [dict(data= [dict(type='scatter',
                           x=df.Date[:k+1],
                           y=low[:k+1]),
                      dict(type='scatter',
                           x=df.Date[:k+1],
                           y=high[:k+1])],
               traces= [0, 1],  #this means that  frames[k]['data'][0]  updates trace1, and   frames[k]['data'][1], trace2 
              )for k  in  range(1, len(low)-1)] 

layout = go.Layout(width=650,
                   height=400,
                   showlegend=False,
                   hovermode='closest',
                   updatemenus=[dict(type='buttons', showactive=False,
                                y=1.05,
                                x=1.15,
                                xanchor='right',
                                yanchor='top',
                                pad=dict(t=0, r=10),
                                buttons=[dict(label='Play',
                                              method='animate',
                                              args=[None, 
                                                    dict(frame=dict(duration=3, 
                                                                    redraw=False),
                                                         transition=dict(duration=0),
                                                         fromcurrent=True,
                                                         mode='immediate')])])])


layout.update(xaxis =dict(range=[df.Date[0], df.Date[len(df)-1]], autorange=False),
              yaxis =dict(range=[min(low)-0.5, high.max()+0.5], autorange=False));
fig = go.Figure(data=[trace1, trace2], frames=frames, layout=layout)
f = fig.full_figure_for_development(warn=False)


fig.data[1].fill = 'tozeroy'

fig.show()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.