Blue Economy Project Visualization
Developed by: Abu Kibria, PhD
NC State University
October 10, 2024
In [45]: import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
# Load data
be_dt = pd.read_excel("Cost by Project Stage.xlsx", sheet_name='kb_grphc')
# Extract columns for each stage
ax_a = be_dt['cost_bucket']
ay_p1 = be_dt['proj_scp_feasb']
ay_p2 = be_dt['proj_set_vald']
ay_p3 = be_dt['proj_dev']
ay_p4 = be_dt['mont_verif']
ay_p5 = be_dt['crdt_issu']
ay_p6 = be_dt['crdt_sale']
# Set font family for the entire plot
plt.rcParams["font.family"] = "Arial"
plt.rcParams["font.size"] = 11
# Create subplots with shared y-axis and shared x-axis
fig, axes = plt.subplots(nrows=1, ncols=6, figsize=(15, 6), sharey=True, sharex=Tr
# Colorblind-friendly color palette
colorblind_palette = sns.color_palette("colorblind")
# Plot each horizontal bar chart in a separate axis
bars1 = axes[0].barh(ax_a, ay_p1, color=colorblind_palette[0])
axes[0].set_title('Feasibility')
bars2 = axes[1].barh(ax_a, ay_p2, color=colorblind_palette[1])
axes[1].set_title('Validation')
bars3 = axes[2].barh(ax_a, ay_p3, color=colorblind_palette[2])
axes[2].set_title('Development')
bars4 = axes[3].barh(ax_a, ay_p4, color=colorblind_palette[3])
axes[3].set_title('Verification')
bars5 = axes[4].barh(ax_a, ay_p5, color=colorblind_palette[4])
axes[4].set_title('Credit Issue')
bars6 = axes[5].barh(ax_a, ay_p6, color=colorblind_palette[5])
axes[5].set_title('Credit Sale')
# Add the title "Conservation"
fig.suptitle('Conservation', fontsize=16, y=1.03, weight= 'bold')
# Set common labels for x and y axes
fig.text(0.5, .01, 'USD', ha='center', va='center', fontsize=12) # Common x-axis
fig.text(0.04, 0.5, '', ha='center', va='center', rotation='vertical', fontsize=12
# Set individual tick parameters
for ax in axes:
ax.tick_params(axis='x', labelsize=10) # x-axis now at the bottom
ax.tick_params(axis='y', labelsize=10) # y-axis labels (cost buckets) on the
# Remove top and right spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Remove gap between the graphs by adjusting the layout and setting w_pad to 0
plt.tight_layout(pad=0.5, w_pad=0, h_pad=0) # Adjust rect to remove gaps
# Display the plot
plt.show()
In [47]: import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
# Load data
be_dt = pd.read_excel("Cost by Project Stage.xlsx", sheet_name='kb_grphr')
# Extract columns for each stage
ax_a = be_dt['cost_bucket']
ay_p1 = be_dt['proj_scp_feasb']
ay_p2 = be_dt['proj_set_vald']
ay_p3 = be_dt['proj_dev']
ay_p4 = be_dt['mont_verif']
ay_p5 = be_dt['crdt_issu']
ay_p6 = be_dt['crdt_sale']
# Set font family for the entire plot
plt.rcParams["font.family"] = "Arial"
plt.rcParams["font.size"] = 11
# Create subplots with shared y-axis and shared x-axis
fig, axes = plt.subplots(nrows=1, ncols=6, figsize=(15, 6), sharey=True, sharex=Tr
# Colorblind-friendly color palette
colorblind_palette = sns.color_palette("colorblind")
# Plot each horizontal bar chart in a separate axis
bars1 = axes[0].barh(ax_a, ay_p1, color=colorblind_palette[0])
axes[0].set_title('Feasibility')
bars2 = axes[1].barh(ax_a, ay_p2, color=colorblind_palette[1])
axes[1].set_title('Validation')
bars3 = axes[2].barh(ax_a, ay_p3, color=colorblind_palette[2])
axes[2].set_title('Development')
bars4 = axes[3].barh(ax_a, ay_p4, color=colorblind_palette[3])
axes[3].set_title('Verification')
bars5 = axes[4].barh(ax_a, ay_p5, color=colorblind_palette[4])
axes[4].set_title('Credit Issue')
bars6 = axes[5].barh(ax_a, ay_p6, color=colorblind_palette[5])
axes[5].set_title('Credit Sale')
# Add the title "Conservation"
fig.suptitle('Restoration', fontsize=16, y=1.03, weight= 'bold')
# Set common labels for x and y axes
fig.text(0.5, .01, 'USD', ha='center', va='center', fontsize=12) # Common x-axis
fig.text(0.04, 0.5, '', ha='center', va='center', rotation='vertical', fontsize=12
# Set individual tick parameters
for ax in axes:
ax.tick_params(axis='x', labelsize=10) # x-axis now at the bottom
ax.tick_params(axis='y', labelsize=10) # y-axis labels (cost buckets) on the
# Remove top and right spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Remove gap between the graphs by adjusting the layout and setting w_pad to 0
plt.tight_layout(pad=0.5, w_pad=0, h_pad=0) # Adjust rect to remove gaps
# Display the plot
plt.show()
In [61]: import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
# Load data
be_dt = pd.read_excel("Cost by Project Stage.xlsx", sheet_name='Cost_stage')
# Sample data from your be_dt DataFrame
ax_a = be_dt['Project Phase']
ay_p1 = be_dt['Conservation']
ay_p2 = be_dt['Restoration']
prc_grp = be_dt['Price Type']
cost_p_con= be_dt['Conservation %']
cost_p_res= be_dt['Restoration %']
# Set font family and size for the entire plot
plt.rcParams["font.family"] = "Arial"
plt.rcParams["font.size"] = 11
# Create a new figure with two subplots (one for each price type)
price_types = prc_grp.unique()
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 4), sharey=True)
# Colorblind-friendly color palette
colorblind_palette = sns.color_palette("colorblind")
# Set bar width
bar_width = 0.4
# Loop over each price type and plot the bars for Conservation and Restoration
for i, price_type in enumerate(price_types):
ax = axes[i]
# Filter the data based on Price Type
idx = prc_grp == price_type
ax_a_filtered = ax_a[idx]
ay_p1_filtered = ay_p1[idx]
ay_p2_filtered = ay_p2[idx]
# Set bar positions
indices = np.arange(len(ax_a_filtered))
# Plot both sets of bars side by side
bars1 = ax.barh(indices - bar_width / 2, ay_p1_filtered, height=bar_width, col
label='Conservation')
bars2 = ax.barh(indices + bar_width / 2, ay_p2_filtered, height=bar_width, col
label='Restoration')
# Add title and axis labels
ax.set_title(f'{price_type}', fontsize=11, weight='bold')
ax.set_xlabel('USD', fontsize=12)
# Set y-ticks to match the project phases and center them between the bars
ax.set_yticks(indices)
ax.set_yticklabels(ax_a_filtered)
# Add a common legend, adjust position to avoid overlapping with title
handles, labels = axes[0].get_legend_handles_labels()
fig.legend(handles, ['Conservation', 'Restoration'], loc='upper center', fonts
# Customize tick parameters
ax.tick_params(axis='x', labelsize=10)
ax.tick_params(axis='y', labelsize=10)
# Remove top and right spines for cleaner look
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Adjust layout to make sure everything fits
plt.tight_layout()
# Display the plot
plt.show()
In [87]: import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import squarify
# Load data
be_dt = pd.read_excel("Cost by Project Stage.xlsx", sheet_name='Cost_stage')
# Sample data from your be_dt DataFrame
ax_a = be_dt['Project Phase']
cost_p_con = be_dt['Conservation %'].round(2)
cost_p_res = be_dt['Restoration %'].round(2)
prc_grp = be_dt['Price Type']
# Create a mapping of full project phase names to abbreviations (adjust as needed)
abbreviations = {
'Project scoping and feasibility assessment': 'PSFA',
'Project set-up and validation': 'PSV',
'Project development': 'PD',
'Monitoring and verification': 'MV',
'Credit issuance': 'CI',
'Credit sale' : 'CS'
}
# Apply the abbreviation to the Project Phase column
data = pd.DataFrame({
'Project Phase': ax_a.map(abbreviations), # Abbreviated project phase names
'Conservation %': cost_p_con,
'Restoration %': cost_p_res,
'Price Type': prc_grp
})
# Create a new column for labels combining 'Project Phase' and % of costs
data['Label'] = data['Project Phase'] + '\nCon: ' + data['Conservation %'].astype(
# Set font family for the plot
plt.rcParams["font.family"] = "Arial"
plt.rcParams["font.size"] = 10
# Get unique price groups
price_groups = data['Price Type'].unique()
# Create two treemaps, one for each price group
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
for i, price_group in enumerate(price_groups):
ax = axes[i]
# Filter data for the current price group
price_data = data[data['Price Type'] == price_group]
# Set color palette for the treemap
colors = sns.color_palette("coolwarm", n_colors=len(price_data))
# Squarify plot for the current price group
squarify.plot(sizes=price_data['Conservation %'] + price_data['Restoration %']
label=price_data['Label'], color=colors, alpha=0.8, ax=ax)
# Add title
ax.set_title(f'{price_group}', fontsize=11, weight='bold')
# Remove axes
ax.axis('off')
# Adjust layout for better presentation
plt.tight_layout()
# Show plot
plt.show()
In [231… import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
# Load data
be_dt = pd.read_excel("Cost by Project Stage.xlsx", sheet_name='Cost_stage')
# Sample data from your be_dt DataFrame
ax_a = be_dt['Project Phase']
cost_p_con = be_dt['Conservation %'].round(2)
cost_p_res = be_dt['Restoration %'].round(2)
prc_grp = be_dt['Price Type']
# Create a mapping of full project phase names to abbreviations (adjust as needed)
abbreviations = {
'Project scoping and feasibility assessment': 'PSFA',
'Project set-up and validation': 'PSV',
'Project development': 'PD',
'Monitoring and verification': 'MV',
'Credit issuance': 'CI',
'Credit sale' : 'CS'
}
# Apply the abbreviation to the Project Phase column
data = pd.DataFrame({
'Project Phase': ax_a.map(abbreviations), # Abbreviated project phase names
'Conservation %': cost_p_con,
'Restoration %': cost_p_res,
'Price Type': prc_grp
})
# Get unique price groups
price_groups = data['Price Type'].unique()
# Set font family for the plot
plt.rcParams["font.family"] = "Arial"
plt.rcParams["font.size"] = 10
# Colorblind-friendly color palette
colorblind_palette = sns.color_palette("colorblind")
# Create a figure with polar subplots for each price group
fig, axes = plt.subplots(1, 2, subplot_kw=dict(projection='polar'), figsize=(8, 5)
# Iterate through price groups and create separate radial bar plots
for i, price_group in enumerate(price_groups):
ax = axes[i]
# Filter data for the current price group
price_data = data[data['Price Type'] == price_group]
# Number of variables we're plotting
num_vars = len(price_data)
# Compute the angle for each bar, with an offset for separation between Conser
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
angles_con = np.array(angles) - (np.pi / (num_vars * 3)) # Shift Conservation
angles_res = np.array(angles) + (np.pi / (num_vars * 3)) # Shift Restoration
# Set up the width of each bar
width = 2 * np.pi / (num_vars * 4) # Narrower bars to fit side by side
# Plot Conservation % bars
bars1 = ax.bar(angles_con, price_data['Conservation %'], width=width, bottom=0
# Plot Restoration % bars next to Conservation %
bars2 = ax.bar(angles_res, price_data['Restoration %'], width=width, bottom=0,
# Set labels for the radial plot
ax.set_xticks(angles)
ax.set_xticklabels(price_data['Project Phase'], size=10)
# Ensure gridlines are behind bars
ax.grid(linewidth=.5, linestyle='--', zorder=0)
# Set the radial plot's title and add a legend
ax.set_title(f'', fontsize=12, weight=False)
# Add legend outside the polar subplots
handles, labels = axes[0].get_legend_handles_labels()
fig.legend(handles, ['Conservation', 'Restoration'], loc='lower center', fontsize=
# Adjust layout for better presentation
plt.tight_layout()
# Show plot
plt.show()
In [77]: import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
# Load data
be_dt = pd.read_excel("Cost by Project Stage.xlsx", sheet_name='Cost_stage')
# Sample data from your be_dt DataFrame
ax_a = be_dt['Project Phase']
ay_p1 = be_dt['Conservation']
ay_p2 = be_dt['Restoration']
prc_grp = be_dt['Price Type']
cost_p_con = be_dt['Conservation %']
cost_p_res = be_dt['Restoration %']
# Create a mapping of full project phase names to abbreviations (adjust as needed)
abbreviations = {
'Project scoping and feasibility assessment': 'PSFA',
'Project set-up and validation': 'PSV',
'Project development': 'PD',
'Monitoring and verification': 'MV',
'Credit issuance': 'CI',
'Credit sale' : 'CS'
}
# Apply the abbreviation to the Project Phase column
data = pd.DataFrame({
'Project Phase': ax_a.map(abbreviations), # Abbreviated project phase names
'Conservation %': cost_p_con,
'Restoration %': cost_p_res,
'Price Type': prc_grp
})
# Get unique price groups
price_groups = prc_grp.unique()
# Set font family and size for the entire plot
plt.rcParams["font.family"] = "Arial"
plt.rcParams["font.size"] = 10
# Colorblind-friendly color palette
colorblind_palette = sns.color_palette("colorblind")
# Create a 2x2 figure
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 6))
# --- First Plot (Top Left): Horizontal bar plots for Conservation and Restoration
# Loop over each price type and plot the bars for Conservation and Restoration
for i, price_type in enumerate(price_groups):
ax = axes[0, i] # Top row
idx = prc_grp == price_type
ax_a_filtered = ax_a[idx]
ay_p1_filtered = ay_p1[idx]
ay_p2_filtered = ay_p2[idx]
# Set bar positions
indices = np.arange(len(ax_a_filtered))
bar_width = 0.4
# Plot both sets of bars side by side
ax.barh(indices - bar_width / 2, ay_p1_filtered, height=bar_width, color=color
ax.barh(indices + bar_width / 2, ay_p2_filtered, height=bar_width, color=color
# Add title and axis labels
ax.set_title(f'{price_type}', fontsize=11, weight='bold')
ax.set_xlabel('USD', fontsize=10)
# Set y-ticks to match the project phases and center them between the bars
ax.set_yticks(indices)
ax.set_yticklabels(ax_a_filtered)
# Customize tick parameters
ax.tick_params(axis='x', labelsize=8)
ax.tick_params(axis='y', labelsize=10)
# Remove top and right spines for cleaner look
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Add a common legend for the bar plots
handles, labels = axes[0, 0].get_legend_handles_labels()
fig.legend(handles, ['Conservation', 'Restoration'], loc='upper center', fontsize=
# --- Second Plot (Bottom): Polar bar plots for Conservation and Restoration ---
for i, price_group in enumerate(price_groups):
ax = axes[1, i] # Bottom row with polar plots
price_data = data[data['Price Type'] == price_group]
num_vars = len(price_data)
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
angles_con = np.array(angles) - (np.pi / (num_vars * 3))
angles_res = np.array(angles) + (np.pi / (num_vars * 3))
width = 2 * np.pi / (num_vars * 4)
ax = plt.subplot(2, 2, i + 3, projection='polar') # Create a polar subplot
# Plot Conservation % bars
ax.bar(angles_con, price_data['Conservation %'], width=width, bottom=0, color=
# Plot Restoration % bars
ax.bar(angles_res, price_data['Restoration %'], width=width, bottom=0, color=c
# Set labels
ax.set_xticks(angles)
ax.set_xticklabels(price_data['Project Phase'], size=9, fontfamily= 'arial')
ax.grid(linewidth=0.3, linestyle='--', zorder=0, color= 'grey')
ax.spines['polar'].set_visible(False)
# Set the radial plot's title
ax.set_title('', fontsize=12)
# Adjust layout and display
plt.tight_layout()
plt.show()
In [169… import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import seaborn as sns
# Load data
be_dt = pd.read_excel("Cost by Project Stage.xlsx", sheet_name='Cost_stage')
# Extract relevant columns from the DataFrame
ax_a = be_dt['Project Phase']
cost_p_con = be_dt['Conservation %'].round(2)
cost_p_res = be_dt['Restoration %'].round(2)
prc_grp = be_dt['Price Type']
# Data for bar polot
ay_p1br = be_dt['Conservation']
ay_p2br = be_dt['Restoration']
# Create a mapping for abbreviated project phase names
abbreviations = {
'Project scoping and feasibility assessment': 'PSFA',
'Project set-up and validation': 'PSV',
'Project development': 'PD',
'Monitoring and verification': 'MV',
'Credit issuance': 'CI',
'Credit sale': 'CS'
}
# Apply the abbreviation to the Project Phase column
data = pd.DataFrame({
'Project Phase': ax_a.map(abbreviations),
'Conservation %': cost_p_con,
'Restoration %': cost_p_res,
'Price Type': prc_grp
})
# Set font and color palette
plt.rcParams["font.family"] = "Arial"
plt.rcParams["font.size"] = 10
colorblind_palette = sns.color_palette("colorblind")
# Get unique price groups
price_groups = data['Price Type'].unique()
# 2x2 grid for the plots
fig, axes = plt.subplots(2, 2, figsize=(12,8))
# Pie chart for price group 1
ax3 = axes[1, 0]
price_data_1 = data[data['Price Type'] == price_groups[0]]
sizes_3 = price_data_1['Conservation %'] + price_data_1['Restoration %']
labels_3 = price_data_1['Project Phase'] + '\nCon: ' + price_data_1['Conservation
explode_3 = [0.03] * len(sizes_3)
ax3.pie(sizes_3, labels=labels_3, explode=explode_3, autopct='%1.1f%%', textprops=
startangle=65, pctdistance=0.75, labeldistance=1.2, colors=colorblind_pale
ax3.set_title(f'', fontsize=11, weight='bold')
# Pie chart for price group 2
ax4 = axes[1, 1]
price_data_2 = data[data['Price Type'] == price_groups[1]]
sizes_4 = price_data_2['Conservation %'] + price_data_2['Restoration %']
labels_4 = price_data_2['Project Phase'] + '\nCon: ' + price_data_2['Conservation
explode_4 = [0.03] * len(sizes_4)
ax4.pie(sizes_4, labels=labels_4, explode=explode_4, autopct='%1.1f%%', textprops=
startangle=65, pctdistance=0.75, labeldistance=1.2, colors=colorblind_pale
ax4.set_title(f'', fontsize=11, weight='bold')
# Set bar width
bar_width = 0.4
# Horizontal bar charts for Conservation and Restoration (for both price groups)
for i, price_type in enumerate(price_groups):
ax = axes[0, i] # Top row for bar charts
idx = prc_grp == price_type
ax_a_filtered = ax_a[idx]
ay_p1_filtered = ay_p1br[idx]
ay_p2_filtered = ay_p2br[idx]
# Set bar positions
indices = np.arange(len(ax_a_filtered))
# Plot both sets of bars side by side
ax.barh(indices - bar_width / 2, ay_p1_filtered, height=bar_width, color=color
ax.barh(indices + bar_width / 2, ay_p2_filtered, height=bar_width, color=colo
# Add title and axis labels
ax.set_title(f'{price_type}', fontsize=11, weight='bold')
ax.set_xlabel('USD', fontsize=10)
# Set y-ticks to match the project phases
ax.set_yticks(indices)
ax.set_yticklabels(ax_a_filtered.map(abbreviations))
# Customize tick parameters
ax.tick_params(axis='x', labelsize=8)
ax.tick_params(axis='y', labelsize=10)
# Remove top and right spines for cleaner look
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Add a common legend for the bar plots
handles, labels = axes[0, 0].get_legend_handles_labels()
fig.legend(handles, ['Conservation', 'Restoration'], loc='upper center', fontsize=
# Adjust layout for better presentation
plt.tight_layout()
# Show plot
plt.show()
In [5]: import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Load data
be_dt = pd.read_excel("cost per hectare per ecosystem per activity.xlsx", sheet_na
#define x and y coordinates
x = be_dt['Strategy']
y = data
In [35]: import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Load data
be_dt = pd.read_excel("cost per hectare per ecosystem per activity.xlsx", sheet_na
# Prepare the angles and values for the bars
ANGLES = np.linspace(0, 2 * np.pi, len(be_dt), endpoint=False)
VALUES = be_dt["cost_000"].values.round(2)
LABELS = be_dt["Strategy"].values
# Group data by Price Type
price_grps = be_dt['Price Type'].unique()
# Set font family and size
plt.rcParams['font.family'] = 'Arial'
plt.rcParams['font.size'] = 11
# Define data labels
def get_label_rotation(angle, offset):
rotation = np.rad2deg(angle + offset)
if angle <= np.pi:
alignment = "right"
rotation += 180
else:
alignment = "left"
return rotation, alignment
def add_labels(angles, values, labels, offset, ax):
padding = 4
for angle, value, label in zip(angles, values, labels):
rotation, alignment = get_label_rotation(angle, offset)
ax.text(
x=angle,
y=value + padding,
s=label,
ha=alignment,
va="center",
rotation=rotation,
rotation_mode="anchor",
fontsize=10
)
# Group values
GROUP = be_dt["Eco_type"].values
PAD = 0 # Reduced padding to minimize extra bars
ANGLES_N = len(VALUES) + PAD * len(np.unique(GROUP))
ANGLES = np.linspace(1, 2 * np.pi, num=ANGLES_N, endpoint=False)
WIDTH = (1 * np.pi) / len(ANGLES)
# Offset to start bars at pi/2 (90 degrees)
OFFSET = np.pi / 2
# Calculate group sizes
GROUPS_SIZE = [len(group) for _, group in be_dt.groupby("Eco_type")]
# Determine indexes for each group
offset = 0
IDXS = []
for size in GROUPS_SIZE:
IDXS.extend(range(offset + PAD, offset + size + PAD))
offset += size + PAD
# Plotting
fig, ax = plt.subplots(figsize=(8, 7), subplot_kw={"projection": "polar"}) # Keep
ax.set_theta_offset(OFFSET)
ax.set_ylim(-100, 100)
ax.set_frame_on(False)
ax.xaxis.grid(False)
ax.yaxis.grid(False)
ax.set_xticks([])
ax.set_yticks([])
# Assign colors based on Price Type
# Define two colors: one for each type of price group
colorblind_palette = sns.color_palette("colorblind")
color1 = colorblind_palette[8] # Blue
color2 = colorblind_palette[3] # Orange
colors_map = {price_grps[0]: color1, price_grps[1]: color2} # Map price types to
# Create bar plot with assigned colors
COLORS = [colors_map[be_dt['Price Type'].iloc[i]] for i in IDXS] # Assign colors
ax.bar(
ANGLES[IDXS], VALUES, width=WIDTH, color=COLORS,
edgecolor="white", linewidth=2
)
# Add labels to the bars
add_labels(ANGLES[IDXS], VALUES, LABELS, OFFSET, ax)
# Extra customization: group lines and reference annotations
group_rotations = {
"Mangrove": 100, # Rotate Mangrove
"Saltmarsh":740, # Rotate Saltmarsh
"Seagrass": 300 # Rotate Seagrass
}
offset = 0
for group, size in zip(["Mangrove", "Saltmarsh", "Seagrass"], GROUPS_SIZE):
# Add line below bars
x1 = np.linspace(ANGLES[offset + PAD], ANGLES[offset + size + PAD - 1], num=50
ax.plot(x1, [-5] * 50, color="#333333")
# Add text for group name
rotation_angle = group_rotations.get(group, 0)
ax.text(
np.mean(x1), -20, group, color="#333333", fontsize=10, fontfamily='Arial',
fontweight="bold", ha="center", va="center", rotation=rotation_angle
)
# Add reference lines at 20, 40, 60, 80, and 100
for y in range(20, 101, 20):
ax.plot(np.linspace(ANGLES[offset], ANGLES[offset + PAD - 1], num=50), [y]
ax.text(0.55 * np.pi / 2, y + PAD, f"{y}", ha="right", size=7, color="dimg
offset += size + PAD
# Create a legend
handles = [plt.Rectangle((0, 0), 1, 1, color=colors_map[price_type]) for price_typ
ax.legend(handles, price_grps, title="", loc="upper right", fontsize=10, bbox_to_a
# Tight layout to reduce white space
plt.tight_layout()
plt.show()
In [49]: import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Load data
be_dt = pd.read_excel("cost per hectare per ecosystem per activity.xlsx", sheet_na
# Set font family and size
plt.rcParams['font.family'] = 'Arial'
plt.rcParams['font.size'] = 11
# Define data labels
def get_label_rotation(angle, offset):
rotation = np.rad2deg(angle + offset)
if angle <= np.pi:
alignment = "right"
rotation += 180
else:
alignment = "left"
return rotation, alignment
def add_labels(angles, values, labels, offset, ax):
padding = 4
for angle, value, label in zip(angles, values, labels):
rotation, alignment = get_label_rotation(angle, offset)
ax.text(
x=angle,
y=value + padding,
s=label,
ha=alignment,
va="center",
rotation=rotation,
rotation_mode="anchor",
fontsize=10
)
# Group data by Price Type
price_grps = be_dt['Price Type'].unique()
for price_grp in price_grps:
# Filter data for each price group
grp_data = be_dt[be_dt['Price Type'] == price_grp]
# Get values and labels for the group
ANGLES = np.linspace(0, 2 * np.pi, len(grp_data), endpoint=False)
VALUES = grp_data["cost_000"].values.round(2)
LABELS = grp_data["Strategy"].values
# Group values
GROUP = grp_data["Eco_type"].values
PAD = 0 # Reduced padding to minimize extra bars
ANGLES_N = len(VALUES) + PAD * len(np.unique(GROUP))
ANGLES = np.linspace(1, 2 * np.pi, num=ANGLES_N, endpoint=False)
WIDTH = (2 * np.pi) / len(ANGLES)*.5
# Offset to start bars at pi/2 (90 degrees)
OFFSET = np.pi / 2
# Calculate group sizes
GROUPS_SIZE = [len(group) for _, group in grp_data.groupby("Eco_type")]
# Determine indexes for each group
offset = 0
IDXS = []
for size in GROUPS_SIZE:
IDXS.extend(range(offset + PAD, offset + size + PAD))
offset += size + PAD
# Plotting
fig, ax = plt.subplots(figsize=(6, 5), subplot_kw={"projection": "polar"}) #
ax.set_title(f"{price_grp}", size=14) # Add title to each plot
ax.set_theta_offset(OFFSET)
ax.set_ylim(-100, 100)
ax.set_frame_on(False)
ax.xaxis.grid(False)
ax.yaxis.grid(False)
ax.set_xticks([])
ax.set_yticks([])
# Assign colors to groups
COLORS = [f"C{i}" for i, size in enumerate(GROUPS_SIZE) for _ in range(size)]
# Create bar plot
ax.bar(
ANGLES[IDXS], VALUES, width=WIDTH, color=COLORS,
edgecolor="white", linewidth=2
)
# Add labels to the bars
add_labels(ANGLES[IDXS], VALUES, LABELS, OFFSET, ax)
# Extra customization: group lines and reference annotations
offset = 0
group_rotations = {
"Mangrove": 100, # Rotate Mangrove
"Saltmarsh":740, # Rotate Saltmarsh
"Seagrass": 300 # Rotate Seagrass
}
for group, size in zip(["Mangrove", "Saltmarsh", "Seagrass"], GROUPS_SIZE):
# Add line below bars
x1 = np.linspace(ANGLES[offset + PAD], ANGLES[offset + size + PAD - 1], nu
ax.plot(x1, [-5] * 50, color="#333333")
# Add text for group name
rotation_angle = group_rotations.get(group, 0)
ax.text(
np.mean(x1), -20, group, color="#333333", fontsize=10, fontfamily='Ari
fontweight="bold", ha="center", va="center", rotation=rotation_angle
)
# Add reference lines at 20, 40, 60, 80, and 100
for y in range(20, 101, 20):
ax.plot(np.linspace(ANGLES[offset]*.7, ANGLES[offset + PAD - 1], num=5
ax.text(0.5 * np.pi / 2, y + PAD, f"{y}", ha="left", size=7, color="di
offset += size + PAD
# Tight layout to reduce white space
plt.tight_layout()
plt.show()