Skip to content

Commit aeb10e6

Browse files
committed
Fix dotplot size legend layout issue (overlapping circles) without changing DEFAULT_LEGENDS_WIDTH
- Reverts the change to the global DotPlot.DEFAULT_LEGENDS_WIDTH meant to fix layout issue with overlapping circles in the size legend under certain conditions (especially when dendrogram = True). - The legend width is now adjusted locally within the dotplot wrapper function. - This avoids unintended layout changes to other plots and minimizes the number of test images that need to be updated.
1 parent 29227a0 commit aeb10e6

File tree

32 files changed

+13
-6
lines changed

32 files changed

+13
-6
lines changed

src/scanpy/plotting/_dotplot.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class DotPlot(BasePlot):
108108
# default legend parameters
109109
DEFAULT_SIZE_LEGEND_TITLE = "Fraction of cells\nin group (%)"
110110
DEFAULT_COLOR_LEGEND_TITLE = "Mean expression\nin group"
111-
DEFAULT_LEGENDS_WIDTH = 1.7 # inches
111+
DEFAULT_LEGENDS_WIDTH = 1.5 # inches
112112
DEFAULT_PLOT_X_PADDING = 0.8 # a unit is the distance between two x-axis ticks
113113
DEFAULT_PLOT_Y_PADDING = 1.0 # a unit is the distance between two y-axis ticks
114114

@@ -559,7 +559,7 @@ def _plot_size_legend(self, size_legend_ax: Axes):
559559
size_legend_ax.set_title(self.size_title, y=ymax + 0.45, size="small")
560560

561561
xmin, xmax = size_legend_ax.get_xlim()
562-
size_legend_ax.set_xlim(xmin - 0.15, xmax + 0.25)
562+
size_legend_ax.set_xlim(xmin - 0.15, xmax + 0.5)
563563

564564
def _plot_legend(self, legend_ax, return_ax_dict, normalize):
565565
# to maintain the fixed height size of the legends, a
@@ -630,15 +630,20 @@ def _plot_stacked_colorbars(self, fig, colorbar_area_spec, normalize):
630630
n_cbars = len(groups_to_plot)
631631

632632
# Create a sub-grid just for the colorbars
633-
colorbar_gs = colorbar_area_spec.subgridspec(n_cbars, 1, hspace=0.6)
633+
# Create an empty column to keep colorbars at 3/4 of legend width (1.5 like default with dp.legend_width = 2.0)
634+
colorbar_gs = colorbar_area_spec.subgridspec(
635+
n_cbars, 2, hspace=0.6, width_ratios=[3, 1]
636+
)
634637

635638
# Create a dedicated normalizer for the legend
636639
vmin = self.dot_color_df.values.min()
637640
vmax = self.dot_color_df.values.max()
638641
legend_norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
639642

640643
for i, group_name in enumerate(groups_to_plot):
641-
ax = fig.add_subplot(colorbar_gs[i])
644+
ax = fig.add_subplot(
645+
colorbar_gs[i, 0]
646+
) # Place the colorbar Axes in the first, wider column
642647
cmap = colormaps.get_cmap(self.group_cmaps[group_name])
643648
mappable = ScalarMappable(norm=legend_norm, cmap=cmap)
644649

@@ -1163,7 +1168,9 @@ def dotplot( # noqa: PLR0913
11631168
dot_min=dot_min,
11641169
smallest_dot=smallest_dot,
11651170
dot_edge_lw=kwds.pop("linewidth", _empty),
1166-
).legend(colorbar_title=colorbar_title, size_title=size_title)
1171+
).legend(
1172+
colorbar_title=colorbar_title, size_title=size_title, width=2.0
1173+
) # Width 2.0 to avoid size legend circles to overlap
11671174

11681175
if return_fig:
11691176
return dp

tests/_images/dotplot/expected.png

-61 Bytes
Loading
-11 Bytes
Loading
-91 Bytes
Loading
5 Bytes
Loading
-55 Bytes
Loading
769 Bytes
Loading
849 Bytes
Loading
284 Bytes
Loading
230 Bytes
Loading

0 commit comments

Comments
 (0)