@@ -645,7 +645,30 @@ def _u_object_from_v_object(v_object):
645645
646646
647647def _get_plot_objects (args ):
648- if len (args ) > 1 and isinstance (
648+ if len (args ) > 2 and isinstance (
649+ args [2 ], (iris .cube .Cube , iris .coords .Coord )
650+ ):
651+ # three arguments
652+ u_object , v_object1 , v_object2 = args [:3 ]
653+ u1 , v1 = _uv_from_u_object_v_object (u_object , v_object1 )
654+ _ , v2 = _uv_from_u_object_v_object (u_object , v_object2 )
655+ args = args [3 :]
656+ if u1 .size != v1 .size or u1 .size != v2 .size :
657+ msg = "The x and y-axis objects are not all compatible. They should have equal sizes but got ({}: {}), ({}: {}) and ({}: {})"
658+ raise ValueError (
659+ msg .format (
660+ u_object .name (),
661+ u1 .size ,
662+ v_object1 .name (),
663+ v1 .size ,
664+ v_object2 .name (),
665+ v2 .size ,
666+ )
667+ )
668+ u = u1
669+ v = (v1 , v2 )
670+ v_object = (v_object1 , v_object2 )
671+ elif len (args ) > 1 and isinstance (
649672 args [1 ], (iris .cube .Cube , iris .coords .Coord )
650673 ):
651674 # two arguments
@@ -823,6 +846,52 @@ def _draw_1d_from_points(draw_method_name, arg_func, *args, **kwargs):
823846 return result
824847
825848
849+ def _draw_two_1d_from_points (draw_method_name , arg_func , * args , ** kwargs ):
850+ """
851+ This function is equivalend to _draw_two_1d_from_points but expects two
852+ y-axis variables rather than one (such as is required for .fill_between). It
853+ can't be used where the y-axis variables are string coordinates. The y-axis
854+ variable provided first has precedence where the two differ on whether the
855+ axis should be inverted or whether a map should be drawn.
856+ """
857+ # NB. In the interests of clarity we use "u" to refer to the horizontal
858+ # axes on the matplotlib plot and "v" for the vertical axes.
859+
860+ # retrieve the objects that are plotted on the horizontal and vertical
861+ # axes (cubes or coordinates) and their respective values, along with the
862+ # argument tuple with these objects removed
863+ u_object , v_objects , u , vs , args = _get_plot_objects (args )
864+
865+ v_object1 , _ = v_objects
866+ v1 , v2 = vs
867+
868+ # if both u_object and v_object are coordinates then check if a map
869+ # should be drawn
870+ if (
871+ isinstance (u_object , iris .coords .Coord )
872+ and isinstance (v_object1 , iris .coords .Coord )
873+ and _can_draw_map ([v_object1 , u_object ])
874+ ):
875+ # Replace non-cartopy subplot/axes with a cartopy alternative and set
876+ # the transform keyword.
877+ kwargs = _ensure_cartopy_axes_and_determine_kwargs (
878+ u_object , v_object1 , kwargs
879+ )
880+
881+ axes = kwargs .pop ("axes" , None )
882+ draw_method = getattr (axes if axes else plt , draw_method_name )
883+ if arg_func is not None :
884+ args , kwargs = arg_func (u , v1 , v2 , * args , ** kwargs )
885+ result = draw_method (* args , ** kwargs )
886+ else :
887+ result = draw_method (u , v1 , v2 , * args , ** kwargs )
888+
889+ # Invert y-axis if necessary.
890+ _invert_yaxis (v_object1 , axes )
891+
892+ return result
893+
894+
826895def _replace_axes_with_cartopy_axes (cartopy_proj ):
827896 """
828897 Replace non-cartopy subplot/axes with a cartopy alternative
@@ -1599,6 +1668,45 @@ def scatter(x, y, *args, **kwargs):
15991668 return _draw_1d_from_points ("scatter" , _plot_args , * args , ** kwargs )
16001669
16011670
1671+ def fill_between (x , y1 , y2 , * args , ** kwargs ):
1672+ """
1673+ Plots y1 and y2 against x, and fills the space between them.
1674+
1675+ Args:
1676+
1677+ * x: :class:`~iris.cube.Cube` or :class:`~iris.coords.Coord`
1678+ A cube or a coordinate to plot on the x-axis.
1679+
1680+ * y1: :class:`~iris.cube.Cube` or :class:`~iris.coords.Coord`
1681+ First cube or a coordinate to plot on the y-axis.
1682+
1683+ * y2: :class:`~iris.cube.Cube` or :class:`~iris.coords.Coord`
1684+ Second cube or a coordinate to plot on the y-axis.
1685+
1686+ Kwargs:
1687+
1688+ * axes: :class:`matplotlib.axes.Axes`
1689+ The axes to use for drawing. Defaults to the current axes if none
1690+ provided.
1691+
1692+ See :func:`matplotlib.pyplot.fill_between` for details of additional valid
1693+ keyword arguments.
1694+
1695+ """
1696+ # here we are more specific about argument types than generic 1d plotting
1697+ if not isinstance (x , (iris .cube .Cube , iris .coords .Coord )):
1698+ raise TypeError ("x must be a cube or a coordinate." )
1699+ if not isinstance (y1 , (iris .cube .Cube , iris .coords .Coord )):
1700+ raise TypeError ("y1 must be a cube or a coordinate." )
1701+ if not isinstance (y1 , (iris .cube .Cube , iris .coords .Coord )):
1702+ raise TypeError ("y2 must be a cube or a coordinate." )
1703+ args = (x , y1 , y2 ) + args
1704+ _plot_args = None
1705+ return _draw_two_1d_from_points (
1706+ "fill_between" , _plot_args , * args , ** kwargs
1707+ )
1708+
1709+
16021710# Provide convenience show method from pyplot
16031711show = plt .show
16041712
0 commit comments