@@ -14,8 +14,8 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
1414 **plot_kwargs:
1515 color_col=None
1616 raw_marker_size=6, es_marker_size=9,
17- swarm_label=None, contrast_label=None,
18- swarm_ylim=None, contrast_ylim=None,
17+ swarm_label=None, contrast_label=None, delta_label=None,
18+ swarm_ylim=None, contrast_ylim=None, delta_ylim=None,
1919 custom_palette=None, swarm_desat=0.5, halfviolin_desat=1,
2020 halfviolin_alpha=0.8,
2121 float_contrast=True,
@@ -298,7 +298,14 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
298298 gridspec_kw = {"width_ratios" : width_ratios_ga ,
299299 "wspace" : 0 },
300300 ** init_fig_kwargs )
301-
301+ rawdata_axes = axx [0 ]
302+ contrast_axes = axx [1 ]
303+ elif delta2 :
304+ fig = plt .subplots (gridspec_kw = {"hspace" : 0.3 },
305+ ** init_fig_kwargs )
306+ rawdata_axes = plt .subplot2grid ((2 ,3 ), (0 ,0 ), colspan = 3 )
307+ contrast_axes = plt .subplot2grid ((2 ,3 ), (1 ,0 ), colspan = 2 )
308+ delta_axes = plt .subplot2grid ((2 ,3 ), (1 ,2 ))
302309 else :
303310 fig , axx = plt .subplots (nrows = 2 ,
304311 gridspec_kw = {"hspace" : 0.3 },
@@ -309,11 +316,12 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
309316 contrast_ax_ylim_low = list ()
310317 contrast_ax_ylim_high = list ()
311318 contrast_ax_ylim_tickintervals = list ()
312- rawdata_axes = axx [0 ]
313- contrast_axes = axx [1 ]
319+ rawdata_axes = axx [0 ]
320+ contrast_axes = axx [1 ]
314321 rawdata_axes .set_frame_on (False )
315322 contrast_axes .set_frame_on (False )
316-
323+ if delta2 :
324+ delta_axes .set_frame_on (False )
317325 redraw_axes_kwargs = {'colors' : ytick_color ,
318326 'facecolors' : ytick_color ,
319327 'lw' : 1 ,
@@ -464,8 +472,8 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
464472
465473 # plot one more halfviolin graph if the plot is for delta-delta
466474 if delta2 :
467- ticks_to_plot . append ( ticks_to_plot [ - 1 ] + 2 )
468- ticks_to_skip . append ( ticks_to_skip [ - 1 ] + 2 )
475+ ticks_to_plot_delta = [ 0 ]
476+ ticks_to_skip_delta = [ 1 ]
469477
470478 # Plot the bootstraps, then the effect sizes and CIs.
471479 es_marker_size = plot_kwargs ["es_marker_size" ]
@@ -474,7 +482,7 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
474482
475483 results = EffectSizeDataFrame .results
476484 contrast_xtick_labels = []
477-
485+
478486 for j , tick in enumerate (ticks_to_plot ):
479487 current_group = results .test [j ]
480488 current_control = results .control [j ]
@@ -513,25 +521,65 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
513521 contrast_xtick_labels .append ("{}\n minus\n {}" .format (current_group ,
514522 current_control ))
515523
524+ # plot delta-delta violin
525+ if delta2 :
526+ current_group = results .test [2 ]
527+ current_control = results .control [2 ]
528+ current_bootstrap = results .bootstraps [2 ]
529+ current_effsize = results .difference [2 ]
530+ current_ci_low = results .bca_low [2 ]
531+ current_ci_high = results .bca_high [2 ]
532+
533+ # Create the violinplot.
534+ # New in v0.2.6: drop negative infinities before plotting.
535+ v = delta_axes .violinplot (current_bootstrap [~ np .isinf (current_bootstrap )],
536+ positions = [0.5 ],
537+ ** violinplot_kwargs )
538+ # Turn the violinplot into half, and color it the same as the swarmplot.
539+ # Do this only if the color column is not specified.
540+ # Ideally, the alpha (transparency) fo the violin plot should be
541+ # less than one so the effect size and CIs are visible.
542+ if bootstraps_color_by_group is True :
543+ fc = plot_palette_contrast [current_group ]
544+ else :
545+ fc = "grey"
546+
547+ halfviolin (v , fill_color = fc , alpha = halfviolin_alpha )
548+
549+ # Plot the effect size.
550+ delta_axes .plot ([0.5 ], current_effsize , marker = 'o' ,
551+ color = ytick_color ,
552+ markersize = es_marker_size )
553+ # Plot the confidence interval.
554+ delta_axes .plot ([0.5 , 0.5 ],
555+ [current_ci_low , current_ci_high ],
556+ linestyle = "-" ,
557+ color = ytick_color ,
558+ linewidth = group_summary_kwargs ['lw' ])
559+
560+ delta_xtick_labels = "{}\n minus\n {}" .format (current_group ,
561+ current_control )
562+
516563
517564 # Make sure the contrast_axes x-lims match the rawdata_axes xlims,
518565 # and add an extra violinplot tick for delta-delta plot.
519- raw_x_stick = rawdata_axes .get_xticks ()
566+ contrast_axes .set_xticks (rawdata_axes .get_xticks ())
567+
520568 if delta2 :
521- raw_x_stick = np .append (raw_x_stick , max (raw_x_stick )+ 1 )
522- raw_x_stick = np .append (raw_x_stick , max (raw_x_stick )+ 1 )
523- contrast_axes .set_xticks (raw_x_stick )
569+ delta_axes .set_xticks ([0 ,0.5 ])
524570
525571 if show_pairs is True :
526572 max_x = contrast_axes .get_xlim ()[1 ]
527573 rawdata_axes .set_xlim (- 0.375 , max_x )
528574
529575 if float_contrast is True :
530576 contrast_axes .set_xlim (0.5 , 1.5 )
531- elif not is_paired and delta2 :
577+ elif delta2 :
578+ contrast_axes .set_xlim (rawdata_axes .get_xlim ())
532579 temp = rawdata_axes .get_xlim ()
533- contrast_axes .set_xlim (temp [0 ], temp [1 ]+ 2 )
534580 rawdata_axes .set_xlim (temp [0 ], temp [1 ]+ 2 )
581+ delta_axes .set_xlim (- 0.5 , 1 )
582+ delta_axes .set_xticklabels (["" , delta_xtick_labels ])
535583 else :
536584 contrast_axes .set_xlim (rawdata_axes .get_xlim ())
537585
@@ -711,7 +759,7 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
711759 contrast_axes .set_ylim (low , high )
712760 else :
713761 contrast_axes .set_ylim (custom_contrast_ylim )
714-
762+
715763 # If 0 lies within the ylim of the contrast axes,
716764 # draw a zero reference line.
717765 contrast_axes_ylim = contrast_axes .get_ylim ()
@@ -722,11 +770,35 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
722770 if contrast_ylim_low < 0 < contrast_ylim_high :
723771 contrast_axes .axhline (y = 0 , ** reflines_kwargs )
724772
725- if is_paired == "baseline" and show_pairs == True :
726- if delta2 :
727- temp_ticks_to_skip = ticks_to_skip [:- 1 ]
773+
774+ if delta2 and plot_kwargs ['delta_ylim' ] is not None :
775+ custom_delta_ylim = plot_kwargs ['delta_ylim' ]
776+
777+ if len (custom_delta_ylim ) != 2 :
778+ err1 = "Please check `delta_ylim` consists of "
779+ err2 = "exactly two numbers."
780+ raise ValueError (err1 + err2 )
781+
782+ if effect_size_type == "cliffs_delta" :
783+ # Ensure the ylims for a cliffs_delta plot never exceed [-1, 1].
784+ l = plot_kwargs ['delta_ylim' ][0 ]
785+ h = plot_kwargs ['delta_ylim' ][1 ]
786+ low = - 1 if l < - 1 else l
787+ high = 1 if h > 1 else h
788+ delta_axes .set_ylim (low , high )
728789 else :
729- temp_ticks_to_skip = ticks_to_skip
790+ delta_axes .set_ylim (custom_delta_ylim )
791+
792+ if delta2 :
793+ delta_axes_ylim = delta_axes .get_ylim ()
794+ if delta_axes_ylim [0 ] < delta_axes_ylim [1 ]:
795+ delta_ylim_low , delta_ylim_high = delta_axes_ylim
796+ else :
797+ delta_ylim_high , delta_ylim_low = delta_axes_ylim
798+ if delta_ylim_low < 0 < delta_ylim_high :
799+ delta_axes .axhline (y = 0 , xmin = 0.25 , xmax = 1.5 , ** reflines_kwargs )
800+
801+ if is_paired == "baseline" and show_pairs == True :
730802 rightend_ticks_raw = np .array ([len (i )- 1 for i in temp_idx ]) + np .array (temp_ticks_to_skip )
731803 for ax in [rawdata_axes ]:
732804 sns .despine (ax = ax , bottom = True )
@@ -744,8 +816,6 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
744816 del redraw_axes_kwargs ['y' ]
745817
746818 temp_length = [(len (i )- 1 )* 2 - 1 for i in idx ]
747- if delta2 :
748- temp_length .append (1 )
749819 rightend_ticks_contrast = np .array (temp_length ) + np .array (ticks_to_skip_contrast )
750820 for ax in [contrast_axes ]:
751821 sns .despine (ax = ax , bottom = True )
@@ -763,61 +833,38 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
763833 del redraw_axes_kwargs ['y' ]
764834 else :
765835 # Compute the end of each x-axes line.
766- # Compute the end of each x-axes line.
767- if delta2 :
768- temp = np .array ([len (i )- 1 for i in idx ])
769- temp = np .append (temp , 1 )
770- rightend_ticks = np .array (temp ) + np .array (ticks_to_skip )
771- else :
772- rightend_ticks = np .array ([len (i )- 1 for i in idx ]) + np .array (ticks_to_skip )
773- if not delta2 :
774- for ax in [rawdata_axes , contrast_axes ]:
775- sns .despine (ax = ax , bottom = True )
776-
777- ylim = ax .get_ylim ()
778- xlim = ax .get_xlim ()
779- redraw_axes_kwargs ['y' ] = ylim [0 ]
780-
781- for k , start_tick in enumerate (ticks_to_skip ):
782- end_tick = rightend_ticks [k ]
783- ax .hlines (xmin = start_tick , xmax = end_tick ,
784- ** redraw_axes_kwargs )
785-
786- ax .set_ylim (ylim )
787- del redraw_axes_kwargs ['y' ]
788- else :
789- for ax in [rawdata_axes ]:
790- sns .despine (ax = ax , bottom = True )
791-
792- ylim = ax .get_ylim ()
793- xlim = ax .get_xlim ()
794- redraw_axes_kwargs ['y' ] = ylim [0 ]
836+ rightend_ticks = np .array ([len (i )- 1 for i in idx ]) + np .array (ticks_to_skip )
837+ for ax in [rawdata_axes , contrast_axes ]:
838+ sns .despine (ax = ax , bottom = True )
839+
840+ ylim = ax .get_ylim ()
841+ xlim = ax .get_xlim ()
842+ redraw_axes_kwargs ['y' ] = ylim [0 ]
795843
796- for k , start_tick in enumerate (ticks_to_skip [: - 1 ] ):
797- end_tick = rightend_ticks [k ]
798- ax .hlines (xmin = start_tick , xmax = end_tick ,
844+ for k , start_tick in enumerate (ticks_to_skip ):
845+ end_tick = rightend_ticks [k ]
846+ ax .hlines (xmin = start_tick , xmax = end_tick ,
799847 ** redraw_axes_kwargs )
800848
801- ax .set_ylim (ylim )
802- del redraw_axes_kwargs ['y' ]
803-
804- for ax in [contrast_axes ]:
805- sns .despine (ax = ax , bottom = True )
806-
807- ylim = ax .get_ylim ()
808- xlim = ax .get_xlim ()
809- redraw_axes_kwargs ['y' ] = ylim [0 ]
810-
811- for k , start_tick in enumerate (ticks_to_skip ):
812- end_tick = rightend_ticks [k ]
813- ax .hlines (xmin = start_tick , xmax = end_tick ,
814- ** redraw_axes_kwargs )
849+ ax .set_ylim (ylim )
850+ del redraw_axes_kwargs ['y' ]
851+
852+ if delta2 :
853+ rightend_ticks = np .array ([len (i )- 1 for i in idx ]) + np .array (ticks_to_skip )
815854
816- ax .set_ylim (ylim )
817- del redraw_axes_kwargs ['y' ]
818-
855+ sns .despine (ax = delta_axes , bottom = True )
856+ ylim_contrast = contrast_axes .get_ylim ()
857+ ylim_delta = delta_axes .get_ylim ()
858+ ylim = (min (ylim_contrast [0 ], ylim_delta [0 ]), max (ylim_contrast [1 ], ylim_delta [1 ]))
819859
860+ xlim = delta_axes .get_xlim ()
861+ redraw_axes_kwargs ['y' ] = ylim [0 ]
820862
863+ delta_axes .hlines (xmin = 0 , xmax = 0.5 , ** redraw_axes_kwargs )
864+
865+ delta_axes .set_ylim (ylim )
866+ contrast_axes .set_ylim (ylim )
867+ del redraw_axes_kwargs ['y' ]
821868
822869 # Set raw axes y-label.
823870 swarm_label = plot_kwargs ['swarm_label' ]
@@ -833,7 +880,7 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
833880 'hedges_g' : "Hedges' g" ,
834881 'cliffs_delta' : "Cliff's delta" }
835882 default_contrast_label = contrast_label_dict [EffectSizeDataFrame .effect_size ]
836-
883+
837884 if plot_kwargs ['contrast_label' ] is None :
838885 if is_paired :
839886 contrast_label = "paired\n {}" .format (default_contrast_label )
@@ -847,6 +894,14 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
847894 if float_contrast is True :
848895 contrast_axes .yaxis .set_label_position ("right" )
849896
897+ if delta2 :
898+ if plot_kwargs ['delta_label' ] is None :
899+ delta_label = "delta - delta"
900+ else :
901+ delta_label = plot_kwargs ['delta_label' ]
902+ delta_axes .yaxis .tick_right ()
903+ delta_axes .set_ylabel (delta_label )
904+ delta_axes .yaxis .set_label_position ("right" )
850905
851906 # Set the rawdata axes labels appropriately
852907 rawdata_axes .set_ylabel (swarm_label )
@@ -873,12 +928,19 @@ def EffectSizeDataFramePlotter(EffectSizeDataFrame, **plot_kwargs):
873928 og_ylim_contrast [0 ], og_ylim_contrast [1 ],
874929 ** redraw_axes_kwargs )
875930
876-
931+ if delta2 :
932+ og_xlim_delta = delta_axes .get_xlim ()
933+ og_ylim_delta = delta_axes .get_ylim ()
934+ delta_axes .vlines (og_xlim_delta [1 ],
935+ og_ylim_delta [0 ], og_ylim_delta [1 ],
936+ ** redraw_axes_kwargs )
877937
878938 # Make sure no stray ticks appear!
879939 rawdata_axes .xaxis .set_ticks_position ('bottom' )
880940 rawdata_axes .yaxis .set_ticks_position ('left' )
881941 contrast_axes .xaxis .set_ticks_position ('bottom' )
942+ if delta2 :
943+ delta_axes .xaxis .set_ticks_position ('bottom' )
882944 if float_contrast is False :
883945 contrast_axes .yaxis .set_ticks_position ('left' )
884946
0 commit comments