Black Lives Matter. Please consider donating to Black Girls Code today.

Need animation example with Scattermapbox

Hey,

Can anyone post a simple example of animating points on a mapbox map (Scattermapbox) using plotly python? There is an example here (https://plot.ly/~jackluo/2181/us-wind-turbine-dataset-animation-using/), but it’s very long and involved and hard to follow.
Even a simple example of moving a point from one location to another with a few points in between would be greatly appreciated!
Would also make sense to add this example to the animations examples docs page (https://plot.ly/python/animations/).

Thanks!

This is also cross-posted on stackoverflow here: https://stackoverflow.com/questions/49861760/creating-an-animation-with-plotly-pythoon-and-mapbox

@gideonshalev Recently I answered a similar question here on Plotly forum, and posted this notebook as example https://plot.ly/~empet/14825

Thanks @empet! But I still get an error when running your code offline. Online seems to be fine, but using offline mode, I get this stack trace:


PlotlyDictKeyError Traceback (most recent call last)
~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/tools.py in return_figure_from_figure_or_data(figure_or_data, validate_figure)
1453 try:
-> 1454 graph_objs.Figure(figure)
1455 except exceptions.PlotlyError as err:

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in init(self, *args, **kwargs)
1174 def init(self, *args, **kwargs):
-> 1175 super(Figure, self).init(*args, **kwargs)
1176 if ‘data’ not in self:

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in init(self, *args, **kwargs)
376 for key, val in d.items():
–> 377 self.setitem(key, val, _raise=_raise)
378

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in setitem(self, key, value, _raise)
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)):

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in _value_to_graph_object(self, key, value, _raise)
542 return GraphObjectFactory.create(key, value, _raise=_raise,
–> 543 _parent=self, _parent_key=key)
544

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in create(object_name, *args, **kwargs)
792 if class_name in [‘Figure’, ‘Data’, ‘Frames’]:
–> 793 return globals()[class_name](*args, **kwargs)
794 else:

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in init(self, *args, **kwargs)
157 for index, value in enumerate(list(*args)):
–> 158 value = self._value_to_graph_object(index, value, _raise=_raise)
159

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in _value_to_graph_object(self, index, value, _raise)
1306 return super(Frames, self)._value_to_graph_object(index, value,
-> 1307 _raise=_raise)
1308

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in _value_to_graph_object(self, index, value, _raise)
222 _parent=self,
–> 223 _parent_key=index, **value)
224 except exceptions.PlotlyGraphObjectError:

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in create(object_name, *args, **kwargs)
798 else:
–> 799 return PlotlyDict(*args, **kwargs)
800

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in init(self, *args, **kwargs)
376 for key, val in d.items():
–> 377 self.setitem(key, val, _raise=_raise)
378

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in setitem(self, key, value, _raise)
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)):

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in _value_to_graph_object(self, key, value, _raise)
542 return GraphObjectFactory.create(key, value, _raise=_raise,
–> 543 _parent=self, _parent_key=key)
544

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in create(object_name, *args, **kwargs)
792 if class_name in [‘Figure’, ‘Data’, ‘Frames’]:
–> 793 return globals()[class_name](*args, **kwargs)
794 else:

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in init(self, *args, **kwargs)
157 for index, value in enumerate(list(*args)):
–> 158 value = self._value_to_graph_object(index, value, _raise=_raise)
159

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in _value_to_graph_object(self, index, value, _raise)
1074 _parent=self,
-> 1075 _parent_key=index, **value)
1076

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in create(object_name, *args, **kwargs)
798 else:
–> 799 return PlotlyDict(*args, **kwargs)
800

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in init(self, *args, **kwargs)
376 for key, val in d.items():
–> 377 self.setitem(key, val, _raise=_raise)
378

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in setitem(self, key, value, _raise)
427 path = self._get_path() + (key, )
–> 428 raise exceptions.PlotlyDictKeyError(self, path)
429 return

PlotlyDictKeyError: ‘lat’ is not allowed in ‘scatter’

Path To Error: [‘frames’][0][‘data’][0][‘lat’]

Valid attributes for ‘scatter’ at path [‘frames’][0][‘data’][0] under parents [‘figure’, ‘frames’, ‘frames_entry’, ‘data’]:

['cliponaxis', 'connectgaps', 'customdata', 'customdatasrc', 'dx',
'dy', 'error_x', 'error_y', 'fill', 'fillcolor', 'hoverinfo',
'hoverinfosrc', 'hoverlabel', 'hoveron', 'hovertext', 'hovertextsrc',
'ids', 'idssrc', 'legendgroup', 'line', 'marker', 'mode', 'name',
'opacity', 'r', 'rsrc', 'selected', 'selectedpoints', 'showlegend',
'stream', 't', 'text', 'textfont', 'textposition', 'textpositionsrc',
'textsrc', 'tsrc', 'type', 'uid', 'unselected', 'visible', 'x', 'x0',
'xaxis', 'xcalendar', 'xsrc', 'y', 'y0', 'yaxis', 'ycalendar', 'ysrc']

Run <scatter-object>.help('attribute') on any of the above.
‘’ is the object at [‘frames’][0][‘data’][0]

During handling of the above exception, another exception occurred:

PlotlyError Traceback (most recent call last)
in ()
----> 1 plotly.offline.iplot(fig)

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/offline/offline.py in iplot(figure_or_data, show_link, link_text, validate, image, filename, image_width, image_height, config)
330 config.setdefault(‘linkText’, link_text)
331
–> 332 figure = tools.return_figure_from_figure_or_data(figure_or_data, validate)
333
334 # Though it can add quite a bit to the display-bundle size, we include

~/.pyenv/versions/3.6.2/lib/python3.6/site-packages/plotly/tools.py in return_figure_from_figure_or_data(figure_or_data, validate_figure)
1462 "plot option.\nHere’s why you’re "
1463 “seeing this error:\n\n{0}”
-> 1464 “”.format(err))
1465 if not figure[‘data’]:
1466 raise exceptions.PlotlyEmptyDataError(

PlotlyError: Invalid ‘figure_or_data’ argument. Plotly will not be able to properly parse the resulting JSON. If you want to send this ‘figure_or_data’ to Plotly anyway (not recommended), you can set ‘validate=False’ as a plot option.
Here’s why you’re seeing this error:

‘lat’ is not allowed in ‘scatter’

Path To Error: [‘frames’][0][‘data’][0][‘lat’]

Valid attributes for ‘scatter’ at path [‘frames’][0][‘data’][0] under parents [‘figure’, ‘frames’, ‘frames_entry’, ‘data’]:

['cliponaxis', 'connectgaps', 'customdata', 'customdatasrc', 'dx',
'dy', 'error_x', 'error_y', 'fill', 'fillcolor', 'hoverinfo',
'hoverinfosrc', 'hoverlabel', 'hoveron', 'hovertext', 'hovertextsrc',
'ids', 'idssrc', 'legendgroup', 'line', 'marker', 'mode', 'name',
'opacity', 'r', 'rsrc', 'selected', 'selectedpoints', 'showlegend',
'stream', 't', 'text', 'textfont', 'textposition', 'textpositionsrc',
'textsrc', 'tsrc', 'type', 'uid', 'unselected', 'visible', 'x', 'x0',
'xaxis', 'xcalendar', 'xsrc', 'y', 'y0', 'yaxis', 'ycalendar', 'ysrc']

Run <scatter-object>.help('attribute') on any of the above.
‘’ is the object at [‘frames’][0][‘data’][0]

@empet - it’s as if there’s a bug in iplot where this stuff just isn’t supported (compared to plot)…
And to clarify, my above stacktrace was using plotly.offline.iplot . The code seems to work offline with plot, but iplot throws that error.

In order to get working with iplot, make the following imports:

from plotly.offline import download_plotlyjs, init_notebook_mode,  iplot, plot
init_notebook_mode(connected=True)

and plot with:

iplot(fig, validate=False)

To control the frame rate (i.e. the speed of animation) choose an adequate duration for your own animation. In my notebook it is 200 in both slider definition and updatemenus.

@empet brilliant! the validate=False option for iplot did it!

Thanks very much!

1 Like

This helped me a lot, thanks!

1 Like

Reviving an old discussion surrounding animating points on a map with a question - is there an easy way to remove previous points after a prescribed amount of time has passed?

Hey @m_m, did you ever get an answer to this? I have a similar use case it sounds like and this would be useful info to have.

@m_m, sorry, I should have been more clear: my use case is that I’m having trouble persisting markers, so somewhat the inverse of your issue. I have data points that are at the millisecond resolution level but I want new points to stay on the map after their time step has passed (although ideally I’d like to control how many time steps must pass before they disappear, but I’ll take persisting forever if it has to be that way).

@m_m and @emigre459 To keep markers displayed only an amount of time t you should
define the frames in the above notebook https://plot.ly/~empet/14825

as follows:

t=5
frames = [dict(data= [dict(type='scattermapbox',
                           lat=lats[: k+1] if k<=t else lats[k-t+1: k+1],
                           lon=lons[:k+1] if k<=t else lons[k-t+1: k+1])],
               traces= [0],
               name='frame{}'.format(k)       
              )for k  in  range(1, len(df))]  
1 Like

Thanks so much @empet! That works quite well and via fig.update({'frames': frames}), I can even just directly apply your frames approach to the fig object produced by plotly express, gaining its built-in slider setup and all that along the way!