If you can provide a minimal reproducible example with a 'cut-down' version of your data it would be a lot easier to answer your question. I have an example from a similar question on stackoverflow (https://stackoverflow.com/a/73696447/12957340) that illustrates one approach to your problem:
# Load libraries
library(tidyverse)
# Load example data
raw_data <- structure(list(Type = c("EY", "EY", "EY", "EY", "EY", "EY", "EY",
"EY", "EY", "EY", "EY", "EY", "EO", "EO", "EO", "EO", "EO", "EO",
"EO", "EO", "EO", "EO", "EO", "EO", "EO", "EO", "EO", "EY", "EY",
"EY", "EY", "EY", "EY", "EY", "EY", "EY", "EY", "EY", "EY", "EO",
"EO", "EO", "EO", "EO", "EO", "EO", "EO", "EO", "EO", "EO", "EO",
"EO", "EO", "EO", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe",
"Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe",
"Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe",
"Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe", "Fe"),
Maturity = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("Before",
"After"), class = "factor"), Mn = c(49.65414679, 30.42267647,
53.57468125, 58.38531743, 11.07088615, 45.10644112, 41.33779076,
18.77426257, 60.36149117, 67.0260032, 38.13116392, 69.58713059,
66.80825471, 30.34496525, 56.90875291, 72.37427455, 22.06855022,
39.26030375, 35.31067394, 24.95698024, 24.88586385, 34.65821779,
56.2750941, 19.56655377, 45.04117517, 44.04604616, 30.4130276,
15.76824315, 21.50636001, 27.25777212, 17.08214603, 14.17493713,
34.24593956, 12.39548126, 23.59787998, 38.42021152, 32.54843776,
18.47119505, 26.05687922, 32.97977895, 16.91703485, 30.0626039,
26.72724955, 17.69433512, 22.34314521, 16.73815161, 13.08749188,
19.60771131, 24.08865106, 34.57472809, 14.94650052, 32.60745327,
29.86439635, 20.71564742, 22.32568148, 18.37220522, 24.22830773,
20.91660251, 20.96486868, 34.25266591, 35.57200211, 14.5736099,
25.67187037, 27.7352539, 42.919751, 27.1949762, 18.94238981,
25.25867502, 31.66215867, 18.1734287, 24.41910112, 12.07438938,
12.85034127, 19.75012923, 35.96030792, 30.07986478, 38.91460672,
41.18492241, 41.68085289, 60.93940724, 49.77930187, 17.56806894,
37.13306953, 47.06926881, 85.62093648, 24.31500546, 22.049633,
40.42923285, 87.53339143, 37.08699364, 38.29525586, 28.00272281,
15.58855204, 37.14164977)), row.names = c(NA, -94L), class = c("tbl_df",
"tbl", "data.frame"))
Functions:
summary_df <- raw_data %>%
mutate(Maturity = ifelse(Maturity == "Before", "a", "x")) %>%
group_by(Type, Maturity) %>%
summarise(max_val = max(density(Mn)[[1]]) + 4) %>%
ungroup()
median.stat <- function(x){
out <- quantile(x, probs = c(0.5))
names(out) <- c("ymed")
return(out)
}
Similar 'problematic' violin plot:
ggplot(raw_data, aes(x = Type, y = Mn, fill = Maturity)) +
geom_violin(trim = FALSE, position="dodge") +
geom_boxplot(width=.1, outlier.shape=NA, position=position_dodge(.9)) +
scale_y_continuous(breaks = seq(0, 100, 25)) +
theme_classic() +
theme(axis.title.x = element_blank(),
axis.ticks.x = element_blank()) +
labs(y="Percent Maturity", x= "") +
geom_text(data = summary_df,
aes(label = Maturity,
y = max_val,
x = Type,
group = Maturity),
position = position_dodge(width = 0.9),
check_overlap = TRUE,
show.legend = FALSE,
inherit.aes = FALSE) +
stat_summary(fun.y = median.stat, geom='point', size = 10, colour = "blue",
position = position_dodge(0.9))
#> Warning: The `fun.y` argument of `stat_summary()` is deprecated as of ggplot2 3.3.0.
#> ℹ Please use the `fun` argument instead.

Remove dots:
ggplot(raw_data, aes(x = Type, y = Mn, fill = Maturity)) +
geom_violin(trim = FALSE, position="dodge") +
geom_boxplot(width=.1, outlier.shape=NA, position=position_dodge(.9)) +
scale_y_continuous(breaks = seq(0, 100, 25)) +
theme_classic() +
theme(axis.title.x = element_blank(),
axis.ticks.x = element_blank()) +
labs(y="Percent Maturity", x= "") +
geom_text(data = summary_df,
aes(label = Maturity,
y = max_val,
x = Type,
group = Maturity),
position = position_dodge(width = 0.9),
check_overlap = TRUE,
show.legend = FALSE,
inherit.aes = FALSE) +
stat_summary(fun.y = median.stat, geom='point', size = 10, colour = "blue",
position = position_dodge(0.9), key_glyph = "blank")

Remove dots, but keep 'colour' legend to specify what the dots represent:
ggplot(raw_data, aes(x = Type, y = Mn, fill = Maturity)) +
geom_violin(trim = FALSE, position="dodge") +
geom_boxplot(width=.1, outlier.shape=NA, position=position_dodge(.9), key_glyph = "boxplot") +
scale_y_continuous(breaks = seq(0, 100, 25)) +
theme_classic() +
theme(axis.title.x = element_blank(),
axis.ticks.x = element_blank()) +
labs(y="Percent Maturity", x= "") +
geom_text(data = summary_df,
aes(label = Maturity,
y = max_val,
x = Type,
group = Maturity),
position = position_dodge(width = 0.9),
check_overlap = TRUE,
show.legend = FALSE,
inherit.aes = FALSE) +
stat_summary(aes(colour = "Median"), fun.y = median.stat,
geom='point', size = 10,
position = position_dodge(0.9)) +
scale_color_manual(values = "blue", name = "Statistics") +
guides(fill = guide_legend(override.aes = list(shape = NA)))

Created on 2023-02-08 with reprex v2.0.2
Hopefully this approach can be adapted to your use-case.