JackMcKew / pandas_alive

Create stunning, animated visualisations with Pandas & Matplotlib as easy as calling `df.plot_animated()`
MIT License
582 stars 100 forks source link

Passing `period_label` to `plot_animated` on a GeoDataFrame has no effect if basemap set. #39

Open hraftery opened 3 years ago

hraftery commented 3 years ago

Describe the bug Plotting a GeoDataFrame using plot_animated takes an optional period_label parameter that can be used to style the date/time label that appears on the graph in each frame. Except, it turns out, if a contextily basemap is specified, as is done with the basemap_format argument. If so, the period_label parameter is ignored and it is not possible to style or position the period label text.

To Reproduce This is as per the documention, with the addition of the period_label argument.

import geopandas
import pandas_alive
import contextily

gdf = geopandas.read_file('data/italy-covid-region.gpkg')
gdf.index = gdf.region
gdf = gdf.drop('region',axis=1)

map_chart = gdf.plot_animated(filename='examples/example-geo-polygon-chart.gif',basemap_format={'source':contextily.providers.Stamen.Terrain}, period_label={'foo':'bar'})

Expected behavior The period_label key-value pairs to be interpreted as they are in the non-geopandas examples in the documentation.

Additional context The following diff on pandas_alive/geocharts.py fixes the issue. Turns out the problem is that the first frame is determined by the number of strings already added to the axes text (where the period label is set), but adding a basemap sets the axes text to the attribution string for that basemap, so there is always already one string already set. I have elected to leave the attribution text be, so the period label can be positioned elsewhere and styled differently so the attribution still appears as desired. A separate flag could be added to remove the attribution is desired.

253,262c260,265
<             num_texts = len(self.ax.texts)
<             if num_texts == 0:
<                 # first frame
<                 self.ax.text(
<                     s=s,
<                     transform=self.ax.transAxes,
<                     **self.get_period_label(self.period_label),
<                 )
<             else:
<                 self.ax.texts[0].set_text(s)
---
> 
>             self.ax.text(
>                 s=s,
>                 transform=self.ax.transAxes,
>                 **self.get_period_label(self.period_label),
>             )