Search code examples
python-3.xcartopy

Is it possible to change the color of an object in cartopy after it has been added?


Problem

I am using cartopy to draw some countries in Python. For this purpose I am using the add_geometry function like this:

geo = ax.add_geometries(geometry,facecolor='ghostwhite', edgecolor='black',crs=data_transf)

I want to be able to change the color of a geometry object that I've added. This way I could do animation with countries changing color without redrawing everything every frame. For example, the countries would all start white and then become blue one after the other.

However, I can't seem to find a way to change the color of the object after it has been added.

What usually works

With a usual plot in maplotlib I would do:

import matplolib.pyplot as plt

line, = plt.plot([1,2,3],[4,5,6],'red') #Plot in red
line.set_color('green') #Change the color to green

Why it doesn't work here

There is no set_colorfunction for a FeatureArtistfrom cartopy added with add_geometries. In fact, it seems that the properties color,facecolor,... do not even exist for a FeatureArtist, as shows a call to matplotlib.artist.getp.

For a plot, the call returns:

>>import matplotlib.artist as mart
>>mart.getp(line)
agg_filter = None
alpha = None
animated = False
antialiased = True
children = []
clip_box = TransformedBbox(     Bbox(x0=0.0, y0=0.0, x1=1.0, ...
clip_on = True
clip_path = None
color = (1.0, 0.0, 0.0, 1.0)
contains = None
dash_capstyle = butt
dash_joinstyle = round
data = (array([1, 2, 3]), array([4, 5, 6]))
drawstyle = default
figure = Figure(640x476)
fillstyle = full
gid = None
in_layout = True
label = _line0
linestyle = -
linewidth = 1.5
marker = None
markeredgecolor = (1.0, 0.0, 0.0, 1.0)
markeredgewidth = 1.0
markerfacecolor = (1.0, 0.0, 0.0, 1.0)
markerfacecoloralt = none
markersize = 6.0
markevery = None
path = Path(array([[ 1.,  4.],        [ 2.,  5.],        ...
path_effects = []
picker = None
pickradius = 5
rasterized = None
sketch_params = None
snap = None
solid_capstyle = projecting
solid_joinstyle = round
transform = CompositeGenericTransform(     TransformWrapper(  ...
transformed_clip_path_and_affine = (None, None)
url = None
visible = True
xdata = [1 2 3]
xydata = [[ 1.  4.]  [ 2.  5.]  [ 3.  6.]]
ydata = [4 5 6]
zorder = 2

And for a geometry:

>>mart.getp(geo)
agg_filter = None
alpha = None
animated = False
children = []
clip_box = TransformedBbox(     Bbox(x0=0.0, y0=0.0, x1=1.0, ...
clip_on = True
clip_path = None
contains = None
figure = Figure(1200x990)
gid = None
in_layout = True
label = 
path_effects = []
picker = None
rasterized = None
sketch_params = None
snap = None
transform = CompositeGenericTransform(     TransformWrapper(  ...
transformed_clip_path_and_affine = (None, None)
url = None
visible = True
zorder = 1

As you can see, there is no colorproperty (or similar) that I can change.


Solution

  • This is definitely lacking in the Cartopy interface. Would you mind opening an issue on the Cartopy issue tracker?

    As a workaround, you can modify a private attribute _kwargs, which seems to work:

    import cartopy.feature as cfeature
    f = ax.add_feature(cfeature.STATES)
    f._kwargs['edgecolor'] = 'blue'
    

    NOTE: This is using a private API, and so may change/break without any warning. This is merely a workaround to get you moving, but I'd strongly encourage you to report the issue so that a proper solution can be added to Cartopy.