def plot_rose(directions, velocities, width_dir, width_vel, metadata=None, flood=None, ebb=None): """ Creates a polar histogram. Direction angles from binned histogram must be specified such that 0 degrees is north. Parameters ---------- directions: array-like Directions in degrees with 0 degrees specified as true north velocities: array-like Velocities in m/s width_dir: float Width of directional bins for histogram in degrees width_vel: float Width of velocity bins for histogram in m/s metadata: dictonary If provided needs keys ['name', 'lat', 'lon'] for plot title and information box on plot flood: float Direction in degrees added to theta ticks ebb: float Direction in degrees added to theta ticks Returns ------- ax: figure Water current rose plot """ assert isinstance(velocities,(np.ndarray, pd.Series)), \ 'velocities must be of type np.ndarry or pd.Series' assert isinstance(directions,(np.ndarray, pd.Series)), \ 'directions must be of type np.ndarry or pd.Series' assert len(velocities) == len(directions), \ 'velocities and directions must have the same length' assert all(velocities.values >= 0),\ 'All velocities must be positive' assert all(directions.values >= 0) and all(directions.values <= 360),\ 'directions must be between 0 and 360 degrees' assert isinstance(flood, (int, float, type(None))), \ 'flood must be of type int or float' assert isinstance(ebb, (int, float, type(None))), \ 'ebb must be of type int or float' if flood: assert flood >=0 and flood <=360,\ 'flood must be between 0 and 360 degrees' if ebb: assert ebb >=0 and ebb <=360,\ 'ebb must be between 0 and 360 degrees' assert isinstance(width_dir, (int, float)), \ 'width_dir must be of type int or float' assert isinstance(width_vel, (int, float)), \ 'width_vel must be of type int or float' assert width_dir >=0 ,\ 'width_dir must be greater than 0' assert width_vel >=0 ,\ 'width_vel must be greater than 0' # Calculate the 2D histogram H, dir_edges, vel_edges = _histogram(directions, velocities, width_dir, width_vel) # Determine number of bins dir_bins = H.shape[0] vel_bins = H.shape[1] # Create the angles thetas = np.arange(0, 2 * np.pi, 2 * np.pi / dir_bins) # Initialize the polar polt ax = _initialize_polar(metadata=metadata, flood=flood, ebb=ebb) # Set bar color based on wind speed colors = plt.cm.viridis(np.linspace(0, 1.0, vel_bins)) # Set the current speed bin label names # Calculate the 2D histogram labels = [ f'{i:.1f}-{j:.1f}' for i, j in zip(vel_edges[:-1], vel_edges[1:]) ] # Initialize the vertical-offset (polar radius) for the stacked bar chart. r_offset = np.zeros(dir_bins) for vel_bin in range(vel_bins): # Plot fist set of bars in all directions ax = plt.bar(thetas, H[:, vel_bin], width=(2 * np.pi / dir_bins), bottom=r_offset, color=colors[vel_bin], label=labels[vel_bin]) # Increase the radius offset in all directions r_offset = r_offset + H[:, vel_bin] # Add the a legend for current speed bins plt.legend(loc='best', title='Velocity bins [m/s]', bbox_to_anchor=(1.29, 1.00), ncol=1) # Get the r-ticks (polar y-ticks) yticks = plt.yticks() # Format y-ticks with units for clarity rticks = [f'{y:.1f}%' for y in yticks[0]] # Set the y-ticks plt.yticks(yticks[0], rticks) return ax
def plot_joint_probability_distribution(directions, velocities, width_dir, width_vel, metadata=None, flood=None, ebb=None): """ Creates a polar histogram. Direction angles from binned histogram must be specified such that 0 is north. Parameters ---------- directions: array-like Directions in degrees with 0 degrees specified as true north velocities: array-like Velocities in m/s width_dir: float Width of directional bins for histogram in degrees width_vel: float Width of velocity bins for histogram in m/s metadata: dictonary If provided needs keys ['name', 'Lat', 'Lon'] for plot title and information box on plot flood: float Direction in degrees added to theta ticks ebb: float Direction in degrees added to theta ticks Returns ------- ax: figure Joint probability distribution """ assert isinstance(velocities,(np.ndarray, pd.Series)), \ 'velocities must be of type np.ndarry or pd.Series' assert isinstance(directions,(np.ndarray, pd.Series)), \ 'directions must be of type np.ndarry or pd.Series' assert len(velocities) == len(directions), \ 'velocities and directions must have the same length' assert all(velocities.values >= 0),\ 'All velocities must be positive' assert all(directions.values >= 0) and all(directions.values <= 360),\ 'directions must be between 0 and 360 degrees' assert isinstance(flood, (int, float, type(None))), \ 'flood must be of type int or float' assert isinstance(ebb, (int, float, type(None))), \ 'ebb must be of type int or float' if flood: assert flood >=0 and flood <=360,\ 'flood must be between 0 and 360 degrees' if ebb: assert ebb >=0 and ebb <=360,\ 'ebb must be between 0 and 360 degrees' assert isinstance(width_dir, (int, float)), \ 'width_dir must be of type int or float' assert isinstance(width_vel, (int, float)), \ 'width_vel must be of type int or float' assert width_dir >=0 ,\ 'width_dir must be greater than 0' assert width_vel >=0 ,\ 'width_vel must be greater than 0' # Calculate the 2D histogram H, dir_edges, vel_edges = _histogram(directions, velocities, width_dir, width_vel) # Initialize the polar polt ax = _initialize_polar(metadata=metadata, flood=flood, ebb=ebb) # Set the current speed bin label names labels = [ f'{i:.1f}-{j:.1f}' for i, j in zip(vel_edges[:-1], vel_edges[1:]) ] # Set vel & dir bins to middle of bin except at ends dir_bins = 0.5 * (dir_edges[1:] + dir_edges[:-1]) # set all bins to middle vel_bins = 0.5 * (vel_edges[1:] + vel_edges[:-1]) # Reset end of bin range to edge of bin dir_bins[0] = dir_edges[0] vel_bins[0] = vel_edges[0] dir_bins[-1] = dir_edges[-1] vel_bins[-1] = vel_edges[-1] # Interpolate the bins back to specific data points z = _interpn((dir_bins, vel_bins), H, np.vstack([directions, velocities]).T, method="splinef2d", bounds_error=False) # Plot the most probable data last idx = z.argsort() # Convert to radians and order points by probability theta, r, z = directions.values[idx] * np.pi / 180., velocities.values[ idx], z[idx] # Create scatter plot colored by probability density sx = ax.scatter(theta, r, c=z, s=5, edgecolor=None) # Create colorbar plt.colorbar(sx, label='Joint Probability [%]') # Get the r-ticks (polar y-ticks) yticks = plt.yticks() # Format y-ticks with units for clarity yticks = [f'{y:.1f} $m/s$' for y in yticks[0]] # Set the y-ticks ax.set_yticklabels(yticks) return ax