<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def choropleth(df, projection=None, hue=None, scheme=None, k=5, cmap='Set1', categorical=False, vmin=None, vmax=None, legend=False, legend_kwargs=None, legend_labels=None, extent=None, figsize=(8, 6), ax=None, **kwargs):
 """ Area aggregation plot. Parameters df : GeoDataFrame The data being plotted. projection : geoplot.crs object instance, optional A geographic projection. For more information refer to `the tutorial page on projections <https://nbviewer.jupyter.org/github/ResidentMario/geoplot/blob/master/notebooks/tutorials/Projections.ipynb>`_. hue : None, Series, GeoSeries, iterable, or str, optional Applies a colormap to the output points. categorical : boolean, optional Set to ``True`` if ``hue`` references a categorical variable, and ``False`` (the default) otherwise. Ignored if ``hue`` is left unspecified. scheme : None or {"quantiles"|"equal_interval"|"fisher_Jenks"}, optional Controls how the colormap bin edges are determined. Ignored if ``hue`` is left unspecified. k : int or None, optional Ignored if ``hue`` is left unspecified. Otherwise, if ``categorical`` is False, controls how many colors to use (5 is the default). If set to ``None``, a continuous colormap will be used. cmap : matplotlib color, optional The `matplotlib colormap <http://matplotlib.org/examples/color/colormaps_reference.html>`_ to be used. Ignored if ``hue`` is left unspecified. vmin : float, optional Values below this level will be colored the same threshold value. Defaults to the dataset minimum. Ignored if ``hue`` is left unspecified. vmax : float, optional Values above this level will be colored the same threshold value. Defaults to the dataset maximum. Ignored if ``hue`` is left unspecified. legend : boolean, optional Whether or not to include a legend. Ignored if neither a ``hue`` nor a ``scale`` is specified. legend_values : list, optional The values to use in the legend. Defaults to equal intervals. For more information see `the Gallery demo <https://residentmario.github.io/geoplot/examples/largest-cities-usa.html>`_. legend_labels : list, optional The names to use in the legend. Defaults to the variable values. For more information see `the Gallery demo <https://residentmario.github.io/geoplot/examples/largest-cities-usa.html>`_. legend_kwargs : dict, optional Keyword arguments to be passed to `the underlying legend <http://matplotlib.org/users/legend_guide.html>`_. extent : None or (minx, maxx, miny, maxy), optional Used to control plot x-axis and y-axis limits manually. figsize : tuple, optional An (x, y) tuple passed to ``matplotlib.figure`` which sets the size, in inches, of the resultant plot. ax : AxesSubplot or GeoAxesSubplot instance, optional A ``matplotlib.axes.AxesSubplot`` or ``cartopy.mpl.geoaxes.GeoAxesSubplot`` instance. Defaults to a new axis. kwargs: dict, optional Keyword arguments to be passed to the underlying ``matplotlib`` `Polygon patches <http://matplotlib.org/api/patches_api.html#matplotlib.patches.Polygon>`_. Returns ------- ``AxesSubplot`` or ``GeoAxesSubplot`` The plot axis Examples -------- A choropleth takes observations that have been aggregated on some meaningful polygonal level (e.g. census tract, state, country, or continent) and displays the data to the reader using color. It is a well-known plot type, and likeliest the most general-purpose and well-known of the specifically spatial plot types. It is especially powerful when combined with meaningful or actionable aggregation areas; if no such aggregations exist, or the aggregations you have access to are mostly incidental, its value is more limited. The ``choropleth`` requires a series of enclosed areas consisting of ``shapely`` ``Polygon`` or ``MultiPolygon`` entities, and a set of data about them that you would like to express in color. A basic choropleth requires geometry, a ``hue`` variable, and, optionally, a projection. .. code-block:: python import geoplot as gplt import geoplot.crs as gcrs gplt.choropleth(polydata, hue='latdep', projection=gcrs.PlateCarree()) .. image:: ../figures/choropleth/choropleth-initial.png Change the colormap with the ``cmap`` parameter. .. code-block:: python gplt.choropleth(polydata, hue='latdep', projection=gcrs.PlateCarree(), cmap='Blues') .. image:: ../figures/choropleth/choropleth-cmap.png If your variable of interest is already `categorical <http://pandas.pydata.org/pandas-docs/stable/categorical.html>`_, you can specify ``categorical=True`` to use the labels in your dataset directly. To add a legend, specify ``legend``. .. code-block:: python gplt.choropleth(boroughs, projection=gcrs.AlbersEqualArea(), hue='BoroName', categorical=True, legend=True) .. image:: ../figures/choropleth/choropleth-legend.png Keyword arguments can be passed to the legend using the ``legend_kwargs`` argument. These arguments will be passed to the underlying ``matplotlib.legend.Legend`` instance (`ref <http://matplotlib.org/api/legend_api.html#matplotlib.legend.Legend>`_). The ``loc`` and ``bbox_to_anchor`` parameters are particularly useful for positioning the legend. Other additional arguments will be passed to the underlying ``matplotlib`` `scatter plot <http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.scatter>`_. .. code-block:: python gplt.choropleth(boroughs, projection=gcrs.AlbersEqualArea(), hue='BoroName', categorical=True, legend=True, legend_kwargs={'loc': 'upper left'}) .. image:: ../figures/choropleth/choropleth-legend-kwargs.png Additional arguments not in the method signature will be passed as keyword parameters to the underlying `matplotlib Polygon patches <http://matplotlib.org/api/patches_api.html#matplotlib.patches.Polygon>`_. .. code-block:: python gplt.choropleth(boroughs, projection=gcrs.AlbersEqualArea(), hue='BoroName', categorical=True, linewidth=0) .. image:: ../figures/choropleth/choropleth-kwargs.png Choropleths default to splitting the data into five buckets with approximately equal numbers of observations in them. Change the number of buckets by specifying ``k``. Or, to use a continuous colormap, specify ``k=None``. In this case a colorbar legend will be used. .. code-block:: python gplt.choropleth(polydata, hue='latdep', cmap='Blues', k=None, legend=True, projection=gcrs.PlateCarree()) .. image:: ../figures/choropleth/choropleth-k-none.png The ``choropleth`` binning methodology is controlled using by `scheme`` parameter. The default is ``quantile``, which bins observations into classes of different sizes but the same numbers of observations. ``equal_interval`` will creates bins that are the same size, but potentially containing different numbers of observations. The more complicated ``fisher_jenks`` scheme is an intermediate between the two. .. code-block:: python gplt.choropleth(census_tracts, hue='mock_data', projection=gcrs.AlbersEqualArea(), legend=True, edgecolor='white', linewidth=0.5, legend_kwargs={'loc': 'upper left'}, scheme='equal_interval') .. image:: ../figures/choropleth/choropleth-scheme.png """

    # Initialize the figure.
    fig = _init_figure(ax, figsize)

    if projection:
        projection = projection.load(df, {
            'central_longitude': lambda df: np.mean(np.array([p.x for p in df.geometry.centroid])),
            'central_latitude': lambda df: np.mean(np.array([p.y for p in df.geometry.centroid]))
        })

        # Set up the axis.
        if not ax:
            ax = plt.subplot(111, projection=projection)
    else:
        if not ax:
            ax = plt.gca()

    # Clean up patches.
    _lay_out_axes(ax, projection)

    # Immediately return if input geometry is empty.
    if len(df.geometry) == 0:
        return ax

    # Set extent.
    extrema = _get_envelopes_min_maxes(df.geometry.envelope.exterior)
    _set_extent(ax, projection, extent, extrema)

    # Format the data to be displayed for input.
    hue = _validate_hue(df, hue)
    if hue is None:
        raise ValueError("No 'hue' specified.")

    # Generate the coloring information, if needed. Follows one of two schemes, categorical or continuous,
    # based on whether or not ``k`` is specified (``hue`` must be specified for either to work).
    if k is not None:
        # Categorical colormap code path.

        # Validate buckets.
        categorical, k, scheme = _validate_buckets(categorical, k, scheme)

        if hue is not None:
            cmap, categories, hue_values = _discrete_colorize(categorical, hue, scheme, k, cmap, vmin, vmax)
            colors = [cmap.to_rgba(v) for v in hue_values]

            # Add a legend, if appropriate.
            if legend:
                _paint_hue_legend(ax, categories, cmap, legend_labels, legend_kwargs)
        else:
            colors = ['steelblue']*len(df)
    elif k is None and hue is not None:
        # Continuous colormap code path.
        hue_values = hue
        cmap = _continuous_colormap(hue_values, cmap, vmin, vmax)
        colors = [cmap.to_rgba(v) for v in hue_values]

        # Add a legend, if appropriate.
        if legend:
            _paint_colorbar_legend(ax, hue_values, cmap, legend_kwargs)

    # Draw the features.
    if projection:
        for color, geom in zip(colors, df.geometry):
            features = ShapelyFeature([geom], ccrs.PlateCarree())
            ax.add_feature(features, facecolor=color, **kwargs)
    else:
        for color, geom in zip(colors, df.geometry):
            try:  # Duck test for MultiPolygon.
                for subgeom in geom:
                    feature = descartes.PolygonPatch(subgeom, facecolor=color, **kwargs)
                    ax.add_patch(feature)
            except (TypeError, AssertionError):  # Shapely Polygon.
                feature = descartes.PolygonPatch(geom, facecolor=color, **kwargs)
                ax.add_patch(feature)

    return ax