示例#1
0
def plot_wind_rose_with_gradient(freq_table, gradient_colors=['#f5faea', '#d6ebad', '#b8dc6f',
                                                              '#9acd32', '#7ba428', '#5c7b1e'], percent_symbol=True):
    table = freq_table.copy()
    import matplotlib as mpl
    sectors = len(table.columns)
    table_binned = pd.DataFrame()
    if isinstance(table.index[0], pd.Interval):
        table.index = [i.mid for i in table.index]
    table_trans = table.T
    table_binned = pd.concat([table_binned, table_trans.loc[:, 0:3].sum(axis=1).rename(3)], axis=1, sort=True)
    table_binned = pd.concat([table_binned, table_trans.loc[:, 4:6].sum(axis=1).rename(6)], axis=1, sort=True)
    table_binned = pd.concat([table_binned, table_trans.loc[:, 7:9].sum(axis=1).rename(9)], axis=1, sort=True)
    table_binned = pd.concat([table_binned, table_trans.loc[:, 10:12].sum(axis=1).rename(12)], axis=1, sort=True)
    table_binned = pd.concat([table_binned, table_trans.loc[:, 13:15].sum(axis=1).rename(15)], axis=1, sort=True)
    table_binned = pd.concat([table_binned, table_trans.loc[:, 16:].sum(axis=1).rename(18)], axis=1, sort=True)
    table_binned = table_binned.T
    fig = plt.figure(figsize=(12, 12))
    ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)
    ax.set_theta_zero_location('N')
    ax.set_theta_direction(-1)
    ax.set_thetagrids(np.arange(0, 360, 360.0/sectors), zorder=2)
    if percent_symbol:
        symbol = '%'
    else:
        symbol = ' '
    ax.set_rgrids(np.linspace(0.1, max(table.sum(axis=0))+2.0, 10),
                  labels=['%.0f' % round(i)+symbol for i in np.linspace(0.1, max(table.sum(axis=0))+2.0, 10)],
                  angle=0, zorder=2)
    direction_bins = utils.get_direction_bin_array(sectors)[1:-2]
    direction_bins = np.insert(direction_bins, 0, direction_bins[-2])
    ax.set_ylim(0, max(table.sum(axis=0))+3.0)
    angular_width = 2*np.pi/sectors - (np.pi/180)  # Leaving 1 degree gap
    ax.bar(0, 1, alpha=0)

    def _choose_color(speed_bin):
        colors = gradient_colors
        bins = [0, 3.5, 6.5, 9.5, 12.5, 15.5, 18.5, 41]
        return colors[np.digitize([speed_bin], bins)[0]-1]
    for column in table_binned:
        radial_pos = 0.0
        angular_pos = (np.pi / 180.0) * float(column.split('-')[0])
        for speed_bin, frequency in zip(table_binned.index, table_binned[column]):
            color = _choose_color(speed_bin)
            patch = mpl.patches.Rectangle((angular_pos, radial_pos), angular_width, frequency, facecolor=color,
                                          edgecolor='#5c7b1e', linewidth=0.3, zorder=3)
            ax.add_patch(patch)
            radial_pos += frequency
    legend_patches = [mpl.patches.Patch(color=gradient_colors[0], label='0-3 m/s'),
                      mpl.patches.Patch(color=gradient_colors[1], label='4-6 m/s'),
                      mpl.patches.Patch(color=gradient_colors[2], label='7-9 m/s'),
                      mpl.patches.Patch(color=gradient_colors[3], label='10-12 m/s'),
                      mpl.patches.Patch(color=gradient_colors[4], label='13-15 m/s'),
                      mpl.patches.Patch(color=gradient_colors[5], label='15+ m/s')]
    ax.legend(handles=legend_patches)
    return ax.get_figure()
示例#2
0
def distribution_by_dir_sector(var_series,
                               direction_series,
                               sectors=12,
                               aggregation_method='%frequency',
                               direction_bin_array=None,
                               direction_bin_labels=None):
    """
    Accepts a series of a variable and  wind direction. Computes the distribution of first variable with respect to
    wind direction sectors

    :param var_series: Series of the variable whose distribution we need to find
    :param direction_series: Series of wind directions between [0-360]
    :param sectors: Number of sectors to bin direction to. The first sector is centered at 0 by default. To change that
            behaviour specify direction_bin_array
    :param aggregation_method: Statistical method used to find distribution it can be mean, max, min, std, count,
            describe, a custom function, etc. Computes frequency in percentages by default
    :param direction_bin_array: Optional, to change default behaviour of first sector centered at 0 assign an array of
            bins to this
    :param direction_bin_labels: Optional, you can specify an array of labels to be used for the bins. uses string
            labels of the format '30-90' by default
    :returns: A DataFrame/series with wind direction sector as row indexes and columns with statistics chosen by
            aggregation_method

    """
    var_series = var_series.dropna()
    direction_series = direction_series.dropna()
    if direction_bin_array is None:
        direction_bin_array = utils.get_direction_bin_array(sectors)
        zero_centered = True
    else:
        sectors = len(direction_bin_array) - 1
        zero_centered = False
    if direction_bin_labels is None:
        direction_bin_labels = _get_direction_bin_labels(
            sectors, direction_bin_array, zero_centered)
    direction_binned_series = _binned_direction_series(direction_series, sectors, direction_bin_array)\
        .rename('direction_bin')
    data = pd.concat([var_series.rename('data'), direction_binned_series],
                     join='inner',
                     axis=1)
    if aggregation_method == '%frequency':
        result = data.groupby([
            'direction_bin'
        ])['data'].count().rename('%frequency') / len(data) * 100.0
    else:
        result = data.groupby(['direction_bin'
                               ])['data'].agg(aggregation_method)

    for i in range(1, sectors + 1):
        if not (i in result.index):
            result[i] = 0.0
    result = result.sort_index()
    result.index = direction_bin_labels
    return result
示例#3
0
def _binned_direction_series(direction_series,
                             sectors,
                             direction_bin_array=None):
    """
    Accepts a series with wind directions and number of sectors  you want to divide.

    :param  direction_series: Series of directions to bin
    :param  sectors: number of direction sectors
    :param direction_bin_array: An optional parameter, if you want custom direction bins pass an array
                        of the bins. If nto specified direction_bins will be centered around 0
    :returns: A series with direction-bins, bins centered around 0 degree by default if direction_bin_array
    is not specified

    """
    if direction_bin_array is None:
        direction_bin_array = utils.get_direction_bin_array(sectors)
    return direction_series.dropna().apply(_map_direction_bin,
                                           bins=direction_bin_array,
                                           sectors=sectors)
示例#4
0
def freq_table(var_series,
               direction_series,
               var_bin_array=np.arange(-0.5, 41, 1),
               sectors=12,
               var_bin_labels=None,
               direction_bin_array=None,
               direction_bin_labels=None,
               freq_as_percentage=True,
               return_data=False):
    """
    Accepts a variable series and direction series and computes a frequency table of percentages. Both variable and
    direction are binned

    :param var_series: Series of variable to be binned
    :param direction_series: Series of wind directions between [0-360]
    :param var_bin_array: Array of numbers where adjacent elements of array form a bin
    :param sectors: Number of sectors to bin direction to. The first sector is centered at 0 by default. To change that
            behaviour specify direction_bin_array
    :param var_bin_labels: Optional, an array of labels to use for variable bins
    :param direction_bin_array: Optional, to change default behaviour of first sector centered at 0 assign an array of
        bins to this
    :param direction_bin_labels: Optional, you can specify an array of labels to be used for the bins. uses string
        labels of the format '30-90' by default
    :param freq_as_percentage: Optional, True by default. Returns the frequency as percentages. To return just the
        count, set to False
    :param return_data:  Set to True if you want the data returned.
    :type return_data: bool
    :returns: A DataFrame with row indexes as variable bins and columns as wind direction bins.

    """
    var_series = var_series.dropna()
    direction_series = direction_series.dropna()
    if direction_bin_array is None:
        direction_bin_array = utils.get_direction_bin_array(sectors)
        zero_centered = True
    else:
        sectors = len(direction_bin_array) - 1
        zero_centered = False
    if direction_bin_labels is None:
        direction_bin_labels = _get_direction_bin_labels(
            sectors, direction_bin_array, zero_centered)
    var_binned_series = pd.cut(var_series,
                               var_bin_array,
                               right=False,
                               labels=var_bin_labels).rename('variable_bin')
    direction_binned_series = _binned_direction_series(
        direction_series, sectors, direction_bin_array).rename('direction_bin')
    data = pd.concat([
        var_series.rename('var_data'), var_binned_series,
        direction_binned_series
    ],
                     axis=1).dropna()
    if freq_as_percentage:
        result = pd.crosstab(data.loc[:, 'variable_bin'],
                             data.loc[:, 'direction_bin']) / len(data) * 100.0
    else:
        result = pd.crosstab(data.loc[:, 'variable_bin'],
                             data.loc[:, 'direction_bin'])
    for i in range(1, sectors + 1):
        if not (i in result.columns):
            result.insert(i - 1, i, 0.0)
    result.columns = direction_bin_labels
    result = result.sort_index()
    if return_data:
        return plt.plot_wind_rose_with_gradient(
            result, percent_symbol=freq_as_percentage), result
    else:
        return plt.plot_wind_rose_with_gradient(
            result, percent_symbol=freq_as_percentage)