问题
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
回答1:
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.
回答2:
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']))
来源:https://stackoverflow.com/questions/43058892/using-plotly-in-jupyter-to-create-animated-chart-in-off-line-mode