Skip to content

Commit 0ef97df

Browse files
authored
Merge pull request matplotlib#18575 from ShawnChen1996/colorbarGridPosition
Colorbar grid position
2 parents 1f8f717 + 6e117ff commit 0ef97df

File tree

3 files changed

+127
-28
lines changed

3 files changed

+127
-28
lines changed

examples/color/colorbar_basics.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@
3232
fig.colorbar(pos, ax=ax1)
3333

3434
# repeat everything above for the negative data
35+
# you can specify location, anchor and shrink the colorbar
3536
neg = ax2.imshow(Zneg, cmap='Reds_r', interpolation='none')
36-
fig.colorbar(neg, ax=ax2)
37+
fig.colorbar(neg, ax=ax2, location='right', anchor=(0, 0.3), shrink=0.7)
3738

3839
# Plot both positive and negative values between +/- 1.2
3940
pos_neg_clipped = ax3.imshow(Z, cmap='RdBu', vmin=-1.2, vmax=1.2,

lib/matplotlib/colorbar.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,35 +1493,51 @@ def make_axes_gridspec(parent, *, location=None, orientation=None,
14931493
kw['orientation'] = loc_settings['orientation']
14941494
location = kw['ticklocation'] = loc_settings['location']
14951495

1496-
pad = loc_settings["pad"]
1496+
anchor = kw.pop('anchor', loc_settings['anchor'])
1497+
panchor = kw.pop('panchor', loc_settings['panchor'])
1498+
pad = kw.pop('pad', loc_settings["pad"])
14971499
wh_space = 2 * pad / (1 - pad)
14981500

1499-
# for shrinking
1500-
pad_s = (1 - shrink) * 0.5
1501-
wh_ratios = [pad_s, shrink, pad_s]
1502-
1503-
if location == "left":
1504-
gs = parent.get_subplotspec().subgridspec(
1505-
1, 2, wspace=wh_space, width_ratios=[fraction, 1-fraction-pad])
1506-
ss_main = gs[1]
1507-
ss_cb = gs[0].subgridspec(3, 1, hspace=0, height_ratios=wh_ratios)[1]
1508-
elif location == "right":
1509-
gs = parent.get_subplotspec().subgridspec(
1510-
1, 2, wspace=wh_space, width_ratios=[1-fraction-pad, fraction])
1511-
ss_main = gs[0]
1512-
ss_cb = gs[1].subgridspec(3, 1, hspace=0, height_ratios=wh_ratios)[1]
1513-
elif location == "top":
1514-
gs = parent.get_subplotspec().subgridspec(
1515-
2, 1, hspace=wh_space, height_ratios=[fraction, 1-fraction-pad])
1516-
ss_main = gs[1]
1517-
ss_cb = gs[0].subgridspec(1, 3, wspace=0, width_ratios=wh_ratios)[1]
1518-
aspect = 1 / aspect
1519-
else: # "bottom"
1520-
gs = parent.get_subplotspec().subgridspec(
1521-
2, 1, hspace=wh_space, height_ratios=[1-fraction-pad, fraction])
1522-
ss_main = gs[0]
1523-
ss_cb = gs[1].subgridspec(1, 3, wspace=0, width_ratios=wh_ratios)[1]
1524-
aspect = 1 / aspect
1501+
if location in ('left', 'right'):
1502+
# for shrinking
1503+
height_ratios = [
1504+
(1-anchor[1])*(1-shrink), shrink, anchor[1]*(1-shrink)]
1505+
1506+
if location == 'left':
1507+
gs = parent.get_subplotspec().subgridspec(
1508+
1, 2, wspace=wh_space,
1509+
width_ratios=[fraction, 1-fraction-pad])
1510+
ss_main = gs[1]
1511+
ss_cb = gs[0].subgridspec(
1512+
3, 1, hspace=0, height_ratios=height_ratios)[1]
1513+
else:
1514+
gs = parent.get_subplotspec().subgridspec(
1515+
1, 2, wspace=wh_space,
1516+
width_ratios=[1-fraction-pad, fraction])
1517+
ss_main = gs[0]
1518+
ss_cb = gs[1].subgridspec(
1519+
3, 1, hspace=0, height_ratios=height_ratios)[1]
1520+
else:
1521+
# for shrinking
1522+
width_ratios = [
1523+
anchor[0]*(1-shrink), shrink, (1-anchor[0])*(1-shrink)]
1524+
1525+
if location == 'bottom':
1526+
gs = parent.get_subplotspec().subgridspec(
1527+
2, 1, hspace=wh_space,
1528+
height_ratios=[1-fraction-pad, fraction])
1529+
ss_main = gs[0]
1530+
ss_cb = gs[1].subgridspec(
1531+
1, 3, wspace=0, width_ratios=width_ratios)[1]
1532+
aspect = 1 / aspect
1533+
else:
1534+
gs = parent.get_subplotspec().subgridspec(
1535+
2, 1, hspace=wh_space,
1536+
height_ratios=[fraction, 1-fraction-pad])
1537+
ss_main = gs[1]
1538+
ss_cb = gs[0].subgridspec(
1539+
1, 3, wspace=0, width_ratios=width_ratios)[1]
1540+
aspect = 1 / aspect
15251541

15261542
parent.set_subplotspec(ss_main)
15271543
parent.set_anchor(loc_settings["panchor"])

lib/matplotlib/tests/test_colorbar.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,3 +623,85 @@ def test_colorbar_int(clim):
623623
im = ax.imshow([[*map(np.int16, clim)]])
624624
fig.colorbar(im)
625625
assert (im.norm.vmin, im.norm.vmax) == clim
626+
627+
628+
def test_anchored_cbar_position_using_specgrid():
629+
data = np.arange(1200).reshape(30, 40)
630+
levels = [0, 200, 400, 600, 800, 1000, 1200]
631+
shrink = 0.5
632+
anchor_y = 0.3
633+
# right
634+
fig, ax = plt.subplots()
635+
cs = ax.contourf(data, levels=levels)
636+
cbar = plt.colorbar(
637+
cs, ax=ax, use_gridspec=True,
638+
location='right', anchor=(1, anchor_y), shrink=shrink)
639+
640+
# the bottom left corner of one ax is (x0, y0)
641+
# the top right corner of one ax is (x1, y1)
642+
# p0: the vertical / horizontal position of anchor
643+
x0, y0, x1, y1 = ax.get_position().extents
644+
cx0, cy0, cx1, cy1 = cbar.ax.get_position().extents
645+
p0 = (y1 - y0) * anchor_y + y0
646+
647+
np.testing.assert_allclose(
648+
[cy1, cy0],
649+
[y1 * shrink + (1 - shrink) * p0, p0 * (1 - shrink) + y0 * shrink])
650+
651+
# left
652+
fig, ax = plt.subplots()
653+
cs = ax.contourf(data, levels=levels)
654+
cbar = plt.colorbar(
655+
cs, ax=ax, use_gridspec=True,
656+
location='left', anchor=(1, anchor_y), shrink=shrink)
657+
658+
# the bottom left corner of one ax is (x0, y0)
659+
# the top right corner of one ax is (x1, y1)
660+
# p0: the vertical / horizontal position of anchor
661+
x0, y0, x1, y1 = ax.get_position().extents
662+
cx0, cy0, cx1, cy1 = cbar.ax.get_position().extents
663+
p0 = (y1 - y0) * anchor_y + y0
664+
665+
np.testing.assert_allclose(
666+
[cy1, cy0],
667+
[y1 * shrink + (1 - shrink) * p0, p0 * (1 - shrink) + y0 * shrink])
668+
669+
# top
670+
shrink = 0.5
671+
anchor_x = 0.3
672+
fig, ax = plt.subplots()
673+
cs = ax.contourf(data, levels=levels)
674+
cbar = plt.colorbar(
675+
cs, ax=ax, use_gridspec=True,
676+
location='top', anchor=(anchor_x, 1), shrink=shrink)
677+
678+
# the bottom left corner of one ax is (x0, y0)
679+
# the top right corner of one ax is (x1, y1)
680+
# p0: the vertical / horizontal position of anchor
681+
x0, y0, x1, y1 = ax.get_position().extents
682+
cx0, cy0, cx1, cy1 = cbar.ax.get_position().extents
683+
p0 = (x1 - x0) * anchor_x + x0
684+
685+
np.testing.assert_allclose(
686+
[cx1, cx0],
687+
[x1 * shrink + (1 - shrink) * p0, p0 * (1 - shrink) + x0 * shrink])
688+
689+
# bottom
690+
shrink = 0.5
691+
anchor_x = 0.3
692+
fig, ax = plt.subplots()
693+
cs = ax.contourf(data, levels=levels)
694+
cbar = plt.colorbar(
695+
cs, ax=ax, use_gridspec=True,
696+
location='bottom', anchor=(anchor_x, 1), shrink=shrink)
697+
698+
# the bottom left corner of one ax is (x0, y0)
699+
# the top right corner of one ax is (x1, y1)
700+
# p0: the vertical / horizontal position of anchor
701+
x0, y0, x1, y1 = ax.get_position().extents
702+
cx0, cy0, cx1, cy1 = cbar.ax.get_position().extents
703+
p0 = (x1 - x0) * anchor_x + x0
704+
705+
np.testing.assert_allclose(
706+
[cx1, cx0],
707+
[x1 * shrink + (1 - shrink) * p0, p0 * (1 - shrink) + x0 * shrink])

0 commit comments

Comments
 (0)