windrose
windrose copied to clipboard
Display relative frequency with "%" format
Hi,
First of all, windrose package is great!
I would like to suggest to add a fmt argument for the relative frequency. I showed the windrose plot to others and the main question was what is the number shown here with a radii_angle. Then I explained I used the normed=True and the numbers there were relative frequency.
So I modified the windrose.py a little bit in section class WindroseAxes(PolarAxes) to add self.normed arg.
I am attaching only the modified class and function below. Just add normed arg and fmtnum = "%.1f",fmtnorm = "%.1f%%" in set_radii_angle and change a little bit in _init_plot.
I believe you could make it looks way better.
class WindroseAxes(PolarAxes):
"""
Create a windrose axes
"""
name = "windrose"
def __init__(self, *args, **kwargs):
"""
See Axes base class for args and kwargs documentation
"""
# Uncomment to have the possibility to change the resolution directly
# when the instance is created
# self.RESOLUTION = kwargs.pop('resolution', 100)
self.rmax = kwargs.pop("rmax", None)
self.theta_labels = kwargs.pop("theta_labels", ["E", "N-E", "N", "N-W", "W", "S-W", "S", "S-E"])
PolarAxes.__init__(self, *args, **kwargs)
self.set_aspect("equal", adjustable="box", anchor="C")
self.radii_angle = 67.5
self.cla()
self.normed = False
@staticmethod
def set_radii_angle(self, fmtnum = "%.1f",fmtnorm = "%.1f%%",**kwargs):
"""
Set the radii labels angle
"""
normed = self.normed
kwargs.pop("labels", None)
angle = kwargs.pop("angle", None)
if angle is None:
angle = self.radii_angle
self.radii_angle = angle
N = 5
rmax = self.get_rmax()
radii = np.linspace(0, rmax, N + 1)
if rmax % N == 0:
fmt = "%d"
elif normed:
fmt = fmtnorm
else:
fmt = fmtnum
radii_labels = [fmt % r for r in radii]
# radii_labels[0] = "" # Removing label 0
self.set_rgrids(
radii=radii[1:], labels=radii_labels[1:], angle=self.radii_angle, **kwargs
)
def _init_plot(self, direction, var, **kwargs):
"""
Internal method used by all plotting commands
Parameters
----------
direction : 1D array,
directions the wind blows from, North centred
var : 1D array,
values of the variable to compute. Typically the wind speeds
Other Parameters
----------------
normed : boolean, default False
blowto : boolean, default False
colors : str or list of str, default None
The colors of the plot.
cmap : color map, default `jet`
A :obj:`matplotlib.cm` colormap for the plot.
Warning! It overrides `colors`.
weibull_factors :
mean_values :
frequency :
kwarg
Any argument accepted by :obj:`matplotlib.pyplot.plot`.
"""
# if weibull factors are entered overwrite direction and var
if "weibull_factors" in kwargs or "mean_values" in kwargs:
if "weibull_factors" in kwargs and "mean_values" in kwargs:
raise TypeError("cannot specify both weibull_factors and mean_values")
statistic_type = "unset"
if "weibull_factors" in kwargs:
statistic_type = "weibull"
val = kwargs.pop("weibull_factors")
elif "mean_values" in kwargs:
statistic_type = "mean"
val = kwargs.pop("mean_values")
if val:
if "frequency" not in kwargs:
raise TypeError(
"specify 'frequency' argument for statistical input"
)
windFrequencies = kwargs.pop("frequency")
if len(windFrequencies) != len(direction) or len(direction) != len(var):
if len(windFrequencies) != len(direction):
raise TypeError("len(frequency) != len(direction)")
elif len(direction) != len(var):
raise TypeError("len(frequency) != len(direction)")
windSpeeds = []
windDirections = []
for dbin in range(len(direction)):
for _ in range(int(windFrequencies[dbin] * 10000)):
if statistic_type == "weibull":
windSpeeds.append(
random.weibullvariate(var[dbin][0], var[dbin][1])
)
elif statistic_type == "mean":
windSpeeds.append(
random.weibullvariate(var[dbin] * 2 / np.sqrt(np.pi), 2)
)
windDirections.append(direction[dbin])
var, direction = windSpeeds, windDirections
# self.cla()
kwargs.pop("zorder", None)
# Init of the bins array if not set
bins = kwargs.pop("bins", None)
if bins is None:
bins = np.linspace(np.min(var), np.max(var), 6)
if isinstance(bins, int):
bins = np.linspace(np.min(var), np.max(var), bins)
bins = np.asarray(bins)
nbins = len(bins)
# Number of sectors
nsector = kwargs.pop("nsector", None)
if nsector is None:
nsector = 16
# Sets the colors table based on the colormap or the "colors" argument
colors = kwargs.pop("colors", None)
cmap = kwargs.pop("cmap", None)
if colors is not None:
if isinstance(colors, str):
colors = [colors] * nbins
if isinstance(colors, (tuple, list)):
if len(colors) != nbins:
raise ValueError("colors and bins must have same length")
else:
if cmap is None:
cmap = mpl.cm.jet
colors = self._colors(cmap, nbins)
# Building the angles list
angles = np.arange(0, -2 * np.pi, -2 * np.pi / nsector) + np.pi / 2
normed = kwargs.pop("normed", False)
self.normed = normed
blowto = kwargs.pop("blowto", False)
# Calm condition
calm_limit = kwargs.pop("calm_limit", None)
if calm_limit is not None:
mask = var > calm_limit
self.calm_count = len(var) - np.count_nonzero(mask)
if normed:
self.calm_count = self.calm_count * 100 / len(var)
var = var[mask]
direction = direction[mask]
# Set the global information dictionnary
self._info["dir"], self._info["bins"], self._info["table"] = histogram(
direction, var, bins, nsector, normed, blowto
)
return bins, nbins, nsector, colors, angles, kwargs
@ttllttttlltt your solution works a treat, thanks! I agree, it is something worth adding to the release version of windrose.py. Below is an example of your suggestion.

Will something like this be merged? It is not possible to understand the plot without the percentage sign at all.
Then I explained I used the normed=True and the numbers there were relative frequency.
@ttllttttlltt to be fair I never felt the need to explain these. With that said, if you want to put a pull request, I can review it and help you out with the details.
Never mind. Sorry for keeping the issue open for a long time.
Never mind. Sorry for keeping the issue open for a long time.
Not a problem. Sometimes I'll do some house cleaning and, hopefully, address some low hanging fruit. It is fine to leave issues open.