diff --git a/LadybugTools_Engine/Python/src/ladybugtools_toolkit/wind.py b/LadybugTools_Engine/Python/src/ladybugtools_toolkit/wind.py index 1060f29e..dfb0737a 100644 --- a/LadybugTools_Engine/Python/src/ladybugtools_toolkit/wind.py +++ b/LadybugTools_Engine/Python/src/ladybugtools_toolkit/wind.py @@ -41,8 +41,10 @@ analysis_period_to_datetimes, describe_analysis_period, ) +from .bhom.logging import CONSOLE_LOGGER from python_toolkit.plot.timeseries import timeseries -from .plot.utilities import contrasting_color, format_polar_plot +from python_toolkit.plot.polar import polar +from .plot.utilities import contrasting_color # pylint: enable=E0401 @@ -1837,13 +1839,13 @@ def plot_windrose( self, ax: plt.Axes = None, directions: int = 36, - other_data: list[float] = None, - other_bins: list[float] = None, - colors: list[str | tuple[float] | Colormap] = None, + value_bins: list[float] = BEAUFORT_CATEGORIES.bins, + colors: list[str | tuple[float] | Colormap] = BEAUFORT_CATEGORIES.cmap, title: str = None, legend: bool = True, ylim: tuple[float] = None, label: bool = False, + **kwargs, ) -> plt.Axes: """Create a wind rose showing wind speed and direction frequency. @@ -1852,12 +1854,9 @@ def plot_windrose( The axes to plot this chart on. Defaults to None. directions (int, optional): The number of directions to use. Defaults to 36. - other_data (list[float], optional): - A list of other data to bin by direction. - If None, then wind speed will be used. - other_bins (list[float]): - The other data bins to use for the histogram. These bins are right inclusive. - If other data is None, then the default Beaufort bins will be used, + value_bins (list[float], optional): + The bins to use for the wind speed values. These bins are right inclusive. + If unset, then the default BEAUFORT_CATEGORIES bins will be used. otherwise 11 evenly spaced bins will be used. colors: (str | tuple[float] | Colormap, optional): A list of colors to use for the other bins. May also be a colormap. @@ -1875,103 +1874,29 @@ def plot_windrose( plt.Axes: The axes object. """ + #deprecation warnings + if kwargs.pop("other_data", None) is not None: + CONSOLE_LOGGER.warning("'other_data' can no longer be used as an argument to plot custom polar plots with the Wind class. Please use the python_toolkit.plot.polar polar() method instead for this functionality.") + + if kwargs.pop("other_bins", None) is not None: + CONSOLE_LOGGER.warning("'other_bins' has been renamed. Please use 'value_bins' in future instead.") + value_bins = kwargs["other_bins"] + if ax is None: _, ax = plt.subplots(subplot_kw={"projection": "polar"}) - # create grouped data for plotting - binned = self.histogram( - directions=directions, - other_data=other_data, - other_bins=other_bins, - density=True, - remove_calm=True, - ) + df = pd.concat([self.ws, self.wd], axis=1) + + df = df[self.ws >= 1e-10] #remove times where the wind speed is calm, as direction doesn't make sense in this context # set colors if colors is None: - if other_data is None: - colors = [ - to_hex(BEAUFORT_CATEGORIES.cmap(i)) - for i in np.linspace(0, 1, len(binned.columns)) - ] - else: - colors = [ - to_hex(plt.get_cmap("viridis")(i)) - for i in np.linspace(0, 1, len(binned.columns)) - ] - if isinstance(colors, str): - colors = plt.get_cmap(colors) - if isinstance(colors, Colormap): - colors = [to_hex(colors(i)) for i in np.linspace(0, 1, len(binned.columns))] - if isinstance(colors, list | tuple): - if len(colors) != len(binned.columns): - raise ValueError( - f"colors must be a list of length {len(binned.columns)}, or a colormap." - ) - - # HACK to ensure that bar ends are curved when using a polar plot. - fig = plt.figure() - rect = [0.1, 0.1, 0.8, 0.8] - hist_ax = plt.Axes(fig, rect) - hist_ax.bar(np.array([1]), np.array([1])) + colors = BEAUFORT_CATEGORIES.cmap if title is None or title == "": - ax.set_title(textwrap.fill(f"{self.source}", 75)) - else: - ax.set_title(title) - - theta_width = np.deg2rad(360 / directions) - patches = [] - color_list = [] - x = theta_width / 2 - for _, data_values in binned.iterrows(): - y = 0 - for n, val in enumerate(data_values.values): - patches.append( - Rectangle( - xy=(x, y), - width=theta_width, - height=val, - alpha=1, - ) - ) - color_list.append(colors[n]) - y += val - if label: - ax.text(x, y, f"{y:0.1%}", ha="center", va="center", fontsize="x-small") - x += theta_width - local_cmap = ListedColormap(np.array(color_list).flatten()) - pc = PatchCollection(patches, cmap=local_cmap) - pc.set_array(np.arange(len(color_list))) - ax.add_collection(pc) - - # construct legend - if legend: - handles = [ - mpatches.Patch(color=colors[n], label=f"{i} to {j}") - for n, (i, j) in enumerate(binned.columns.values) - ] - _ = ax.legend( - handles=handles, - bbox_to_anchor=(1.1, 0.5), - loc="center left", - ncol=1, - borderaxespad=0, - frameon=False, - fontsize="small", - title=binned.columns.name, - title_fontsize="small", - ) - - # set y-axis limits - if ylim is None: - ylim = (0, max(binned.sum(axis=1))) - if len(ylim) != 2: - raise ValueError("ylim must be a tuple of length 2.") - ax.set_ylim(ylim) - ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1)) + title = textwrap.fill(f"{self.source}", 75) - format_polar_plot(ax, yticklabels=True) + ax = polar(data=df, value_column=df.columns[0], direction_column=df.columns[1], ax=ax, directions=directions, value_bins=value_bins, colours=colors, title=title, legend=legend, ylim=ylim, label=label) return ax