diff --git a/pq-tls-benchmark-framework/emulation-exp/code/kex/Makefile b/pq-tls-benchmark-framework/emulation-exp/code/kex/Makefile
index 5bf175f0e18ca92227b6e75c2b3ae43ba708e5db..360865dccbb18ffb8c15ff82930989e60420c67c 100644
--- a/pq-tls-benchmark-framework/emulation-exp/code/kex/Makefile
+++ b/pq-tls-benchmark-framework/emulation-exp/code/kex/Makefile
@@ -13,20 +13,22 @@ LDLIBS  = -lcrypto -lssl
 
 all: s_timer quic_s_timer quic-client-block
 
-# FIXME which optimization level to use?
+# FIXME cleanup compile commands
 s_timer: s_timer.c
-	$(CC) -g -Wall -Wextra -Werror -Wpedantic -O3 -I$(OPENSSL_INCLUDE) -I$(OQS_INCLUDE) $< -L$(INSTALL_DIR) -L$(OQS_LIB) -lssl -lcrypto -ldl -lpthread -loqs -o $@
+	$(CC) -g -Wall -Wextra -Werror -Wpedantic -O3 -Wl,--enable-new-dtags,-rpath=$(INSTALL_DIR)/openssl/lib64 -I$(OPENSSL_INCLUDE) -I$(OQS_INCLUDE) $< -L$(INSTALL_DIR) -L$(OQS_LIB) -lssl -lcrypto -ldl -lpthread -loqs -o $@
 
 run_s_timer: s_timer
 	./s_timer x25519 1
 
-# NOTE ldd quic_s_timer shows wrong libssl -> maybe use RPATH, otherwise always have to specify LD_LIBRARY_PATH
 quic_s_timer: quic_s_timer.c
-	$(CC) $(CFLAGS) -O3 $(LDFLAGS) -o $@ $^ $(LDLIBS)
+	$(CC) $(CFLAGS) -O3 $(LDFLAGS) -Wl,--enable-new-dtags,-rpath=$(INSTALL_DIR)/openssl/lib64 -o $@ $^ $(LDLIBS)
 
 run_quic_s_timer: quic_s_timer
 	LD_LIBRARY_PATH=$(INSTALL_DIR)/openssl/lib64 ./quic_s_timer x25519 1
 
+run_quic_s_timer_in_netns: quic_s_timer
+	sudo ip netns exec cli_ns_1 env LD_LIBRARY_PATH=../tmp/.local/openssl/lib64 ./quic_s_timer mlkem512 10
+
 quic-client-block: quic-client-block.c
 	$(CC) -g -Wall -Wextra -Wpedantic -I$(OPENSSL_INCLUDE) -I$(OQS_INCLUDE) $< -L$(INSTALL_DIR)/openssl/lib64 -L$(OQS_LIB) -lssl -lcrypto -ldl -loqs -o $@
 
diff --git a/pq-tls-benchmark-framework/emulation-exp/code/kex/scripts/generate_graphs.py b/pq-tls-benchmark-framework/emulation-exp/code/kex/scripts/generate_graphs.py
index 37d904803ccb147382575451243bd699da1cd252..c0e75f917527616fa19d57d18ca3dcbf44777d5a 100755
--- a/pq-tls-benchmark-framework/emulation-exp/code/kex/scripts/generate_graphs.py
+++ b/pq-tls-benchmark-framework/emulation-exp/code/kex/scripts/generate_graphs.py
@@ -263,6 +263,33 @@ def filter_data(
     return filtered_data
 
 
+def get_x_axis_column_name(scenario: str) -> str:
+    match scenario:
+        case "duplicate":
+            return "srv_duplicate"
+        case "packetloss":
+            return "srv_pkt_loss"
+        case "delay":
+            return "srv_delay"
+        case "jitter_delay20ms":
+            return "srv_jitter"
+        case "corrupt":
+            return "srv_corrupt"
+        case "reorder":
+            return "srv_reorder"
+        case "rate_both":
+            return "srv_rate"
+        case "rate_client":
+            return "cli_rate"
+        case "rate_server":
+            return "srv_rate"
+        case "static":
+            assert False, "static scenario has no x-axis"
+        case _:
+            print(f"NO MATCH FOUND FOR {scenario}", file=sys.stderr)
+            sys.exit(1)
+
+
 def get_x_axis(scenario, data, length):
     match scenario:
         case "duplicate":
@@ -790,30 +817,55 @@ def plot_distributions(data):
                 sec_level=row["sec_level"],
                 kem_alg=row["kem_alg"],
             )
+            if row["scenario"] == "static":
+                continue
             # print(
             #     f"scenario: {row['scenario']}, protocol: {row['protocol']}, sec_level: {row['sec_level']}, kem_alg: {row['kem_alg']}, len: {len(filtered_data)}"
             # )
 
+            # return the data with removed rows and the ticks for the x-axis
             def remove_rows_of_data(data):
-                # print(data.iloc[0]["scenario"])
-                # print(data)
-                match data.iloc[0]["scenario"]:
-                    case "packetloss":
+                scenario = data.iloc[0]["scenario"]
+                scenario_column_name = get_x_axis_column_name(scenario)
+                match scenario:
+                    case "packetloss" | "duplicate" | "reorder" | "corrupt":
                         # return data where src_packetloss is 0, 4, 8, 12, 16 or 20
-                        return data.query("srv_pkt_loss % 4 == 0")
+                        ldata = data.query(f"{scenario_column_name} % 4 == 0")
+                    case "jitter_delay20ms":
+                        ldata = data[
+                            data[scenario_column_name].isin([0, 3, 7, 12, 15, 20])
+                        ]
+                    case "rate_both" | "rate_client" | "rate_server":
+                        ldata = data[
+                            data[scenario_column_name].isin(
+                                [
+                                    0.1,
+                                    5,
+                                    10,
+                                    100,
+                                ]
+                            )
+                        ]
+                    case "delay":
+                        ldata = data[
+                            data[scenario_column_name].isin([1, 20, 40, 80, 100, 190])
+                        ]
                     case _:
-                        return pd.concat(
+                        print("No case for this scenario:", scenario)
+                        ldata = pd.concat(
                             [
                                 data.iloc[[0]],
                                 data.iloc[3:-4:4],
                                 data.iloc[[-1]],
                             ]
                         )
+                return ldata, ldata[scenario_column_name].to_list()
 
+            tick_values = None
             if filtered:
-                filtered_data = remove_rows_of_data(filtered_data)
+                filtered_data, tick_values = remove_rows_of_data(filtered_data)
                 # print(filtered_data)
-                # if filtered_data.iloc[0]["scenario"] == "packetloss":
+                # if filtered_data.iloc[0]["scenario"] == "jitter_delay20ms":
                 #     exit()
 
             plt.figure()
@@ -821,20 +873,25 @@ def plot_distributions(data):
             x = x.to_list()
             # print(x)
             width = 0.5 if not filtered else 2.5
-            plt.violinplot(
+            vplots = plt.violinplot(
                 filtered_data["measurements"],
                 positions=x,
-                showmedians=True,
+                showmedians=False,
+                showextrema=False,
                 widths=width,
             )
+            for pc in vplots["bodies"]:
+                pc.set_facecolor("blue")
+                pc.set_edgecolor("darkblue")
             # make the median line transparent
             # for pc in plt.gca().collections:
             #     pc.set_alpha(0.5)
 
             plt.ylim(bottom=0)
             if filtered:
-                plt.ylim(bottom=0, top=filtered_data["qtl_95"].max())
-            plt.xlim(left=0)
+                plt.ylim(bottom=0, top=1.5 * filtered_data["qtl_95"].max())
+                plt.xticks(tick_values)
+            plt.xlim(left=-1.5)
             plt.xlabel(row["scenario"])
             plt.ylabel(f"Time-to-first-byte (ms)")