|
133 | 133 | " \n", |
134 | 134 | " return bootstraps, differences, bcalows, bcahighs\n", |
135 | 135 | "\n", |
| 136 | + "def map_effect_attribute(attribute_key):\n", |
| 137 | + " # Check if the attribute key exists in the dictionary\n", |
| 138 | + " effect_attr_map = {\n", |
| 139 | + " \"mean_diff\": \"Mean Difference\",\n", |
| 140 | + " \"median_diff\": \"Median Difference\",\n", |
| 141 | + " \"cliffs_delta\": \"Cliffs Delta\",\n", |
| 142 | + " \"cohens_d\": \"Cohens d\",\n", |
| 143 | + " \"hedges_g\": \"Hedges g\",\n", |
| 144 | + " \"delta_g\": \"Delta g\"\n", |
| 145 | + " }\n", |
| 146 | + " if attribute_key in effect_attr_map:\n", |
| 147 | + " return effect_attr_map[attribute_key]\n", |
| 148 | + " else:\n", |
| 149 | + " raise TypeError(\"The `effect_size` argument must be a string. Please choose from the following effect sizes: `mean_diff`,`median_diff`,`cliffs_delta`,`cohens_d``, and `hedges_g`.\") # Return a default value or message if the key is not found\n", |
136 | 150 | "\n", |
137 | 151 | "def forest_plot(\n", |
138 | 152 | " contrasts: List,\n", |
139 | 153 | " selected_indices: Optional[List] = None,\n", |
140 | 154 | " contrast_type: str = \"delta2\",\n", |
141 | | - " xticklabels: Optional[List] = None,\n", |
142 | 155 | " effect_size: str = \"mean_diff\",\n", |
143 | 156 | " contrast_labels: List[str] = None,\n", |
144 | | - " ylabel: str = \"value\",\n", |
| 157 | + " ylabel: str = \"effect size\",\n", |
145 | 158 | " plot_elements_to_extract: Optional[List] = None,\n", |
146 | 159 | " title: str = \"ΔΔ Forest\",\n", |
147 | 160 | " custom_palette: Optional[Union[dict, list, str]] = None,\n", |
148 | | - " fontsize: int = 20,\n", |
| 161 | + " fontsize: int = 12,\n", |
| 162 | + " title_font_size: int =16,\n", |
149 | 163 | " violin_kwargs: Optional[dict] = None,\n", |
150 | 164 | " marker_size: int = 20,\n", |
151 | 165 | " ci_line_width: float = 2.5,\n", |
152 | | - " zero_line_width: int = 1,\n", |
| 166 | + " desat_violin: float = 1,\n", |
153 | 167 | " remove_spines: bool = True,\n", |
154 | 168 | " ax: Optional[plt.Axes] = None,\n", |
155 | 169 | " additional_plotting_kwargs: Optional[dict] = None,\n", |
156 | 170 | " rotation_for_xlabels: int = 45,\n", |
157 | | - " alpha_violin_plot: float = 0.4,\n", |
| 171 | + " alpha_violin_plot: float = 0.8,\n", |
158 | 172 | " horizontal: bool = False # New argument for horizontal orientation\n", |
159 | 173 | ")-> plt.Figure:\n", |
160 | 174 | " \"\"\" \n", |
|
167 | 181 | " selected_indices : Optional[List], default=None\n", |
168 | 182 | " Indices of specific contrasts to plot, if not plotting all.\n", |
169 | 183 | " analysis_type : str\n", |
170 | | - " the type of analysis (e.g., 'delta2', 'minimeta').\n", |
171 | | - " xticklabels : Optional[List], default=None\n", |
172 | | - " Custom labels for the x-axis ticks.\n", |
| 184 | + " the type of analysis (e.g., 'delta2', 'mini_meta').\n", |
173 | 185 | " effect_size : str\n", |
174 | | - " Type of effect size to plot (e.g., 'mean_diff', 'median_diff').\n", |
| 186 | + " Type of effect size to plot (e.g., 'mean_diff', 'median_diff', `cliffs_delta`,`cohens_d``, and `hedges_g`).\n", |
175 | 187 | " contrast_labels : List[str]\n", |
176 | 188 | " Labels for each contrast.\n", |
177 | 189 | " ylabel : str\n", |
|
186 | 198 | " Custom color palette for the plot.\n", |
187 | 199 | " fontsize : int\n", |
188 | 200 | " Font size for text elements in the plot.\n", |
| 201 | + " title_font_size: int =16\n", |
| 202 | + " Font size for text of plot title.\n", |
189 | 203 | " violin_kwargs : Optional[dict], default=None\n", |
190 | 204 | " Additional arguments for violin plot customization.\n", |
191 | 205 | " marker_size : int\n", |
192 | 206 | " Marker size for plotting mean differences or effect sizes.\n", |
193 | 207 | " ci_line_width : float\n", |
194 | 208 | " Width of confidence interval lines.\n", |
195 | | - " zero_line_width : int\n", |
196 | | - " Width of the line indicating zero effect size.\n", |
197 | 209 | " remove_spines : bool, default=False\n", |
198 | 210 | " If True, removes top and right plot spines.\n", |
199 | 211 | " ax : Optional[plt.Axes], default=None\n", |
|
222 | 234 | " if selected_indices is not None and not isinstance(selected_indices, (list, type(None))):\n", |
223 | 235 | " raise TypeError(\"The `selected_indices` must be a list of integers or `None`.\")\n", |
224 | 236 | " \n", |
| 237 | + " # For the 'contrast_type' parameter\n", |
225 | 238 | " if not isinstance(contrast_type, str):\n", |
226 | | - " raise TypeError(\"The `contrast_type` argument must be a string.\")\n", |
227 | | - " \n", |
228 | | - " if xticklabels is not None and not all(isinstance(label, str) for label in xticklabels):\n", |
229 | | - " raise TypeError(\"The `xticklabels` must be a list of strings or `None`.\")\n", |
230 | | - " \n", |
| 239 | + " raise TypeError(\"The `contrast_type` argument must be a string. Please choose from `delta2` and `mini_meta`.\")\n", |
| 240 | + "\n", |
| 241 | + " # For the 'effect_size' parameter\n", |
231 | 242 | " if not isinstance(effect_size, str):\n", |
232 | | - " raise TypeError(\"The `effect_size` argument must be a string.\")\n", |
| 243 | + " raise TypeError(\"The `effect_size` argument must be a string. Please choose from the following effect sizes: `mean_diff`, `median_diff`, `cliffs_delta`, `cohens_d`, and `hedges_g`.\")\n", |
233 | 244 | " \n", |
234 | 245 | " if contrast_labels is not None and not all(isinstance(label, str) for label in contrast_labels):\n", |
235 | 246 | " raise TypeError(\"The `contrast_labels` must be a list of strings or `None`.\")\n", |
|
252 | 263 | " if not isinstance(ci_line_width, (int, float)) or ci_line_width <= 0:\n", |
253 | 264 | " raise TypeError(\"`ci_line_width` must be a positive integer or float.\")\n", |
254 | 265 | " \n", |
255 | | - " if not isinstance(zero_line_width, (int, float)) or zero_line_width <= 0:\n", |
256 | | - " raise TypeError(\"`zero_line_width` must be a positive integer or float.\")\n", |
257 | | - " \n", |
258 | 266 | " if not isinstance(remove_spines, bool):\n", |
259 | 267 | " raise TypeError(\"`remove_spines` must be a boolean value.\")\n", |
260 | 268 | " \n", |
|
270 | 278 | " if not isinstance(horizontal, bool):\n", |
271 | 279 | " raise TypeError(\"`horizontal` must be a boolean value.\")\n", |
272 | 280 | "\n", |
| 281 | + " if (effect_size and isinstance(effect_size, str)):\n", |
| 282 | + " ylabel = map_effect_attribute(effect_size)\n", |
273 | 283 | " # Load plot data\n", |
274 | 284 | " contrast_plot_data = load_plot_data(contrasts, effect_size, contrast_type)\n", |
275 | 285 | "\n", |
|
311 | 321 | " if custom_palette:\n", |
312 | 322 | " if isinstance(custom_palette, dict):\n", |
313 | 323 | " violin_colors = [\n", |
314 | | - " custom_palette.get(c, sns.color_palette()[0]) for c in contrasts\n", |
| 324 | + " custom_palette.get(c, sns.color_palette()[0]) for c in contrast_labels\n", |
315 | 325 | " ]\n", |
316 | 326 | " elif isinstance(custom_palette, list):\n", |
317 | 327 | " violin_colors = custom_palette[: len(contrasts)]\n", |
|
323 | 333 | " f\"The specified `custom_palette` {custom_palette} is not a recognized Matplotlib palette.\"\n", |
324 | 334 | " )\n", |
325 | 335 | " else:\n", |
326 | | - " violin_colors = sns.color_palette()[: len(contrasts)]\n", |
| 336 | + " violin_colors = sns.color_palette(n_colors=len(contrasts))\n", |
327 | 337 | "\n", |
| 338 | + " violin_colors = [sns.desaturate(color, desat_violin) for color in violin_colors]\n", |
| 339 | + " \n", |
328 | 340 | " for patch, color in zip(v[\"bodies\"], violin_colors):\n", |
329 | 341 | " patch.set_facecolor(color)\n", |
330 | 342 | " patch.set_alpha(alpha_violin_plot)\n", |
331 | | - "\n", |
| 343 | + " if horizontal:\n", |
| 344 | + " ax.plot([0, 0], [0, len(contrasts)+1], 'k', linewidth = 1)\n", |
| 345 | + " else:\n", |
| 346 | + " ax.plot([0, len(contrasts)+1], [0, 0], 'k', linewidth = 1)\n", |
| 347 | + " \n", |
332 | 348 | " # Flipping the axes for plotting based on 'horizontal'\n", |
333 | 349 | " for k in range(1, len(contrasts) + 1):\n", |
334 | 350 | " if horizontal:\n", |
|
341 | 357 | " # Adjusting labels, ticks, and limits based on 'horizontal'\n", |
342 | 358 | " if horizontal:\n", |
343 | 359 | " ax.set_yticks(range(1, len(contrasts) + 1))\n", |
344 | | - " ax.set_yticklabels(contrast_labels, rotation=rotation_for_xlabels, fontsize=fontsize)\n", |
| 360 | + " ax.set_yticklabels(contrast_labels, rotation=0, fontsize=fontsize)\n", |
345 | 361 | " ax.set_xlabel(ylabel, fontsize=fontsize)\n", |
| 362 | + " ax.set_ylim([0.7, len(contrasts) + 0.5])\n", |
346 | 363 | " else:\n", |
347 | 364 | " ax.set_xticks(range(1, len(contrasts) + 1))\n", |
348 | 365 | " ax.set_xticklabels(contrast_labels, rotation=rotation_for_xlabels, fontsize=fontsize)\n", |
349 | 366 | " ax.set_ylabel(ylabel, fontsize=fontsize)\n", |
| 367 | + " ax.set_xlim([0.7, len(contrasts) + 0.5])\n", |
350 | 368 | "\n", |
351 | 369 | " # Setting the title and adjusting spines as before\n", |
352 | | - " ax.set_title(title, fontsize=fontsize)\n", |
| 370 | + " ax.set_title(title, fontsize=title_font_size)\n", |
353 | 371 | " if remove_spines:\n", |
354 | | - " for spine in ax.spines.values():\n", |
355 | | - " spine.set_visible(False)\n", |
356 | | - "\n", |
| 372 | + " if horizontal:\n", |
| 373 | + " ax.spines['left'].set_visible(False)\n", |
| 374 | + " ax.spines['right'].set_visible(False)\n", |
| 375 | + " ax.spines['top'].set_visible(False)\n", |
| 376 | + " else:\n", |
| 377 | + " ax.spines['top'].set_visible(False)\n", |
| 378 | + " ax.spines['bottom'].set_visible(False)\n", |
| 379 | + " ax.spines['right'].set_visible(False)\n", |
357 | 380 | " # Apply additional customizations if provided\n", |
358 | 381 | " if additional_plotting_kwargs:\n", |
359 | 382 | " ax.set(**additional_plotting_kwargs)\n", |
|
0 commit comments