4

I want to make an animate bar graph similar to the following example by plotly: https://plotly.com/python/animations/

I have following code:

fig = px.bar(
  eu_vaccine_df.sort_values('date'), 
  x='country', y='people_vaccinated_per_hundred',
  color='country',
  animation_frame='date',
  animation_group='country',
  hover_name='country',
  range_y=[0,50],
  range_x=[0,30]
)
fig.update_layout(
  template='plotly_dark',
  margin=dict(r=10, t=25, b=40, l=60)
)
fig.show()

I believe the issue has to do with the 'date' column of my dataframe. Currently it is a datetime and has been transformed using pd.to_datetime(covid_df['date']

The error I get is the following:

ValueError                                Traceback (most recent call last)
<ipython-input-185-ff9c8cc72d87> in <module>
      7   hover_name='country',
      8   range_y=[0,50],
----> 9   range_x=[0,30]

     10 )
     11 fig.update_layout(

/opt/conda/lib/python3.7/site-packages/plotly/express/_chart_types.py in bar(data_frame, x, y, color, facet_row, facet_col, facet_col_wrap, facet_row_spacing, facet_col_spacing, hover_name, hover_data, custom_data, text, base, error_x, error_x_minus, error_y, error_y_minus, animation_frame, animation_group, category_orders, labels, color_discrete_sequence, color_discrete_map, color_continuous_scale, range_color, color_continuous_midpoint, opacity, orientation, barmode, log_x, log_y, range_x, range_y, title, template, width, height)
    352         constructor=go.Bar,
    353         trace_patch=dict(textposition="auto"),
--> 354         layout_patch=dict(barmode=barmode),
    355     )
    356 

/opt/conda/lib/python3.7/site-packages/plotly/express/_core.py in make_figure(args, constructor, trace_patch, layout_patch)
   2087     if "template" in args and args["template"] is not None:
   2088         fig.update_layout(template=args["template"], overwrite=True)
-> 2089     fig.frames = frame_list if len(frames) > 1 else []
   2090 
   2091     fig._px_trendlines = pd.DataFrame(trendline_rows)

/opt/conda/lib/python3.7/site-packages/plotly/basedatatypes.py in __setattr__(self, prop, value)
    719         if prop.startswith("_") or hasattr(self, prop):
    720             # Let known properties and private properties through
--> 721             super(BaseFigure, self).__setattr__(prop, value)
    722         else:
    723             # Raise error on unknown public properties

/opt/conda/lib/python3.7/site-packages/plotly/basedatatypes.py in frames(self, new_frames)
   2853 
   2854         # Validate frames
-> 2855         self._frame_objs = self._frames_validator.validate_coerce(new_frames)
   2856 
   2857     # Update

/opt/conda/lib/python3.7/site-packages/_plotly_utils/basevalidators.py in validate_coerce(self, v, skip_invalid)
   2540                     res.append(self.data_class(v_el))
   2541                 elif isinstance(v_el, dict):
-> 2542                     res.append(self.data_class(v_el, skip_invalid=skip_invalid))
   2543                 else:
   2544                     if skip_invalid:

/opt/conda/lib/python3.7/site-packages/plotly/graph_objs/_frame.py in __init__(self, arg, baseframe, data, group, layout, name, traces, **kwargs)
    253         _v = name if name is not None else _v
    254         if _v is not None:
--> 255             self["name"] = _v
    256         _v = arg.pop("traces", None)
    257         _v = traces if traces is not None else _v

/opt/conda/lib/python3.7/site-packages/plotly/basedatatypes.py in __setitem__(self, prop, value)
   4802                 # ### Handle simple property ###
   4803                 else:
-> 4804                     self._set_prop(prop, value)
   4805             else:
   4806                 # Make sure properties dict is initialized

/opt/conda/lib/python3.7/site-packages/plotly/basedatatypes.py in _set_prop(self, prop, val)
   5146                 return
   5147             else:
-> 5148                 raise err
   5149 
   5150         # val is None

/opt/conda/lib/python3.7/site-packages/plotly/basedatatypes.py in _set_prop(self, prop, val)
   5141 
   5142         try:
-> 5143             val = validator.validate_coerce(val)
   5144         except ValueError as err:
   5145             if self._skip_invalid:

/opt/conda/lib/python3.7/site-packages/_plotly_utils/basevalidators.py in validate_coerce(self, v)
   1084                     v = str(v)
   1085                 else:
-> 1086                     self.raise_invalid_val(v)
   1087 
   1088             if self.no_blank and len(v) == 0:

/opt/conda/lib/python3.7/site-packages/_plotly_utils/basevalidators.py in raise_invalid_val(self, v, inds)
    285                 typ=type_str(v),
    286                 v=repr(v),
--> 287                 valid_clr_desc=self.description(),
    288             )
    289         )

ValueError: 
     Invalid value of type 'pandas._libs.tslibs.timestamps.Timestamp' received for the 'name' property of frame
            Received value: Timestamp('2020-12-13 00:00:00')
    
        The 'name' property is a string and must be specified as:
          - A string
          - A number that will be converted to a string

1 Answers1

10

You should check your "date" column's type (more on this at the bottom of this post). For example, the following code works as a whole.

import plotly.express as px
import pandas as pd

url = 'https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/vaccinations.csv'
df = pd.read_csv(url)

country = 'location'
fig = px.bar(
  df.sort_values('date'), 
  x=country, y='people_vaccinated_per_hundred',
  color=country,
  animation_frame='date',
  animation_group=country,
  hover_name=country,
  range_y=[0,50],
  range_x=[0,30]
)
fig.update_layout(
  template='plotly_dark',
  margin=dict(r=10, t=25, b=40, l=60)
)
fig.show()

plotly

I am assuming though, that your dataset's "date" column is not a string. To check if it's a string vs. another type (this line evaluates to str already, for the above dataset):

type(df['date'][0])

To create a column that is the date converted to a string, put this line before the fig assignment line:

df['date_str'] = df['date'].apply(lambda x: str(x))

Then, in the fig assignment line, the animation frame will need to be set to the name of the new column (e.g. animation_frame='date_str').

ELinda
  • 2,658
  • 1
  • 10
  • 9
  • It worked! for _ in range(1000): print("Thank you ELinda :D") – Sebastian ten Berge Mar 25 '21 at 21:15
  • The code worked, but I now realized that the dates are no longer linear. It now takes the year 2021 dates first and then once those are done it switches to the year 2020. So they are no longer indexed correctly. Any Idea on how to correct this? – Sebastian ten Berge Apr 04 '21 at 13:42
  • Seems like if it is in YYYY-mm-dd format, it should be in order? – ELinda Apr 04 '21 at 14:28
  • I believe it should be in the order as you said. The first transformation I do in my dataframe is the following: covid_df["date"] = pd.to_datetime(covid_df["date"], format = '%Y-%m-%d') following that I do the transformation to the string: eu_vaccine_df['date_str'] = eu_vaccine_df['date'].apply(lambda x: str(x)) I explained the issue in more depth in a new question: https://stackoverflow.com/questions/66942176/python-plotly-px-animation-frame-date-is-in-wrong-order – Sebastian ten Berge Apr 04 '21 at 16:00