def get_shape_areas(df_shapes, shape_i_columns, signed=False):
    '''
    Return a `pandas.Series` indexed by `shape_i_columns` (i.e., each entry
    corresponds to a single shape/polygon), containing the following columns
    the area of each shape.

    If `signed=True`, a positive area value corresponds to a clockwise loop,
    whereas a negative area value corresponds to a counter-clockwise loop.
    '''
    # Make a copy of the SVG data frame since we need to add columns to it.
    df_i = df_shapes.copy()
    df_i['vertex_count'] = (df_i.groupby(shape_i_columns)['x']
                            .transform('count'))
    df_i['area_a'] = df_i.x
    df_i['area_b'] = df_i.y

    # Vector form of [Shoelace formula][1].
    #
    # [1]: http://en.wikipedia.org/wiki/Shoelace_formula
    df_i.loc[df_i.vertex_i == df_i.vertex_count - 1, 'area_a'] *= df_i.loc[df_i.vertex_i == 0, 'y'].values
    df_i.loc[df_i.vertex_i < df_i.vertex_count - 1, 'area_a'] *= df_i.loc[df_i.vertex_i > 0, 'y'].values

    df_i.loc[df_i.vertex_i == df_i.vertex_count - 1, 'area_b'] *= df_i.loc[df_i.vertex_i == 0, 'x'].values
    df_i.loc[df_i.vertex_i < df_i.vertex_count - 1, 'area_b'] *= df_i.loc[df_i.vertex_i > 0, 'x'].values

    area_components = df_i.groupby(shape_i_columns)[['area_a', 'area_b']].sum()
    shape_areas = .5 * (area_components['area_b'] - area_components['area_a'])

    if not signed:
        shape_areas.name = 'area'
        return shape_areas.abs()
    else:
        shape_areas.name = 'signed_area'
        return shape_areas