2024-08-05 22:10:34 +09:00

187 lines
5.3 KiB
Python

import os
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from queuesim.paramset import ExperimentID, SessionID
BOXPLOT_VALUE_VARS = [
"dtime_min",
"dtime_25%",
"dtime_50%",
"dtime_mean",
"dtime_75%",
"dtime_max",
]
PARAM_SET = [
"num_nodes",
"peering_degree",
"min_queue_size",
"transmission_rate",
"num_sent_msgs",
"num_senders",
]
def draw_plots(
df: pd.DataFrame, exp_id: ExperimentID, session_id: SessionID, outdir: str
):
assert os.path.exists(outdir)
__overview_by_queue_type(df, exp_id, session_id, f"{outdir}/plot_overview.png")
num_nodes = int(df["num_nodes"].min())
for param in ["peering_degree", "min_queue_size", "transmission_rate"]:
__impact_of_param_by_queue_type(
df, exp_id, session_id, num_nodes, param, f"{outdir}/plot_{param}.png"
)
if exp_id == ExperimentID(2) or exp_id == ExperimentID(4):
__impact_of_param_by_queue_type(
df,
exp_id,
session_id,
num_nodes,
"num_sent_msgs",
f"{outdir}/plot_num_sent_msgs.png",
)
if exp_id == ExperimentID(3) or exp_id == ExperimentID(4):
__impact_of_param_by_queue_type(
df,
exp_id,
session_id,
num_nodes,
"num_senders",
f"{outdir}/plot_num_senders.png",
)
def __overview_by_queue_type(
df: pd.DataFrame,
exp_id: ExperimentID,
session_id: SessionID,
out_path: str,
):
df = df.drop_duplicates(subset=["num_nodes", "queue_type"])
print(df)
__draw_plot_by_queue_type(
df, f"{exp_id.name}: {session_id.name}: Overview", out_path
)
def __impact_of_param_by_queue_type(
df: pd.DataFrame,
exp_id: ExperimentID,
session_id: SessionID,
num_nodes: int,
param: str,
out_path: str,
):
df = pd.DataFrame(df[df["num_nodes"] == num_nodes])
df = df.drop_duplicates(subset=[param, "queue_type"])
print(df)
__draw_plot_by_queue_type(
df,
f"{exp_id.name}: {session_id.name}: Impact of {param} ({num_nodes} nodes)",
out_path,
)
def __draw_plot_by_queue_type(
df: pd.DataFrame, title: str, out_path: str, legend_columns: list[str] = PARAM_SET
):
# Add a column that will be used as a legend
def __create_legend_value(row):
legend = ""
for i, param in enumerate(legend_columns):
if i > 0:
legend += ", "
legend += f"{param}:{row[param]}"
return legend
df["legend"] = df.apply(__create_legend_value, axis=1)
# Prepare DataFrame in long format for seaborn boxplot
long_format_df = pd.melt(
df,
id_vars=["queue_type", "legend"],
value_vars=BOXPLOT_VALUE_VARS,
var_name="dtime_metric",
value_name="dtime",
)
# Plotting
plt.figure(figsize=(15, 10))
sns.boxplot(data=long_format_df, x="queue_type", y="dtime", hue="legend")
plt.title(title)
plt.xlabel("Queue Type")
plt.ylabel("Dissemination Time")
plt.legend(loc="upper right", ncol=1)
# Adding vertical grid lines between x elements
plt.grid(axis="y")
plt.gca().set_xticks(
[i - 0.5 for i in range(1, len(df["queue_type"].unique()))], minor=True
)
plt.grid(which="minor", axis="x", linestyle="--")
plt.tight_layout()
# Save the plot as a PNG file
assert not os.path.exists(out_path)
plt.savefig(out_path)
plt.draw()
print(f"Saved plot to {out_path}")
def draw_cross_experiment_plots(dfs: list[pd.DataFrame], outdir: str):
assert os.path.exists(outdir)
assert len(dfs) == len(ExperimentID)
# Common filtering conditions
common_conditions = {
"num_nodes": 80,
"peering_degree": 16,
"min_queue_size": 40,
"transmission_rate": 40,
}
# Define the filtering conditions for each DataFrame
conditions = [
{"num_senders": 1, "num_sent_msgs": 1},
{"num_senders": 1, "num_sent_msgs": 8},
{"num_senders": 8, "num_sent_msgs": 1},
{"num_senders": 8, "num_sent_msgs": 8},
]
filtered_dfs: list[pd.DataFrame] = []
for exp_idx, (df, condition) in enumerate(zip(dfs, conditions)):
# Combine common and specific conditions
all_conditions = {**common_conditions, **condition}
# Filter the DataFrame
filtered_df = pd.DataFrame(
df[
(df["num_nodes"] == all_conditions["num_nodes"])
& (df["peering_degree"] == all_conditions["peering_degree"])
& (df["min_queue_size"] == all_conditions["min_queue_size"])
& (df["transmission_rate"] == all_conditions["transmission_rate"])
& (df["num_senders"] == all_conditions["num_senders"])
& (df["num_sent_msgs"] == all_conditions["num_sent_msgs"])
]
)
filtered_df["experiment"] = ExperimentID(exp_idx + 1).value
filtered_dfs.append(
pd.DataFrame(
filtered_df[
["experiment"] + PARAM_SET + ["queue_type"] + BOXPLOT_VALUE_VARS
]
)
)
__draw_plot_by_queue_type(
pd.concat(filtered_dfs),
"Comparisons by Experiment and Queue Type",
f"{outdir}/cross_experiment_plot.png",
legend_columns=["experiment"] + PARAM_SET,
)