Troy
Troy

Reputation: 548

Reduce the size of pyplot subplot by scaling

I am using Julia v.0.6.0, with Juno+Atom IDE, and I am trying to make subplots with PyPlot package, v2.3.2. (Pretty new to this)

Consider the following MWE:

using PyPlot

fig = figure("Test subplots",figsize=(9,9)) 
subplot(2,2,1) 
title("Plot 221")
fig[:add_subplot](2,2,2,polar="true")
title("Plot 222") 
fig[:canvas][:draw]() # Update the figure
suptitle("2x2 Subplot",fontsize=15)
tight_layout(pad=2) 

which yields me this:

subplots

Note how the second subplot is too big such that its title is too close to the polar plot.

What I want to achieve is to have the subplot 222 to still take up the same amount of space in the grid, but to have the polar plot scaled down in size, perhaps to 0.9 of its current size. Note that this should not affect the size of rectangular grid in subplot 221 as well.

Is there an argument that I am missing from the matplotlib documentation?

Upvotes: 0

Views: 790

Answers (1)

Tasos Papastylianou
Tasos Papastylianou

Reputation: 22255

The main thing here is to capture any subplot axes, title objects etc into 'handles', so that you can manipulate their properties individually in an easy manner. So change your initial code like so:

using PyPlot
fig = figure("Test subplots",figsize=(9,9)) 
subplot(2,2,1) 
title("Plot 221")
S = subplot(2,2,2,polar="true")               ## captured
T = title("Plot 222")                         ## captured
fig[:canvas][:draw]() # Update the figure
ST = suptitle("2x2 Subplot",fontsize=15)      ## captured
tight_layout(pad=2) 

Now you can use properties such as T[:get_verticalalignment] to inspect, and T[:set_verticalalignment] to set it to one of "center", "bottom", "top" or "baseline" (as per the matplotlib documentation). E.g.

T[:set_verticalalignment]("bottom")
ST[:set_verticalalignment]("center")

seems to get the amount of separation you'd probably expect.

Alternatively, for even finer control, you can inspect or change the absolute positioning (and implicitly the size) for S, T, or ST via their [:get_position] and [:set_position] methods respectively.

These methods accept either via a normal array denoting [start_x, start_y, width_x, width_y], or a Bbox, which is the form returned by the get methods above, therefore you might want to get that object from matplotlib:

Bbox = PyPlot.matplotlib[:transforms][:Bbox]

Now you can do stuff like this:

# inspect the object's position
S[:get_position]()
#> PyObject Bbox([[0.544201388889, 0.517261679293], 
#>                [0.943952721661, 0.917013012065]])

# absolute positioning using 'width' notation
S[:set_position]([0.51, 0.51, 0.4, 0.4])   

# absolute positioning using a 'Bbox' (note 2D array input, not a vector!)
S[:set_position](Bbox([0.51 0.51; 0.89 0.89]))

# 'relative' by adjusting current position, and wrapping back in a Bbox
S[:set_position](Bbox( S[:get_position]()[:get_points]() + [0.1 0.1; -0.1 -0.1]))

# inspect title position
T[:get_position]()
#> (0.5, 1.05)

# raise title a bit higher (manually)
T[:set_position]([0.5, 1.10])

etc.

Upvotes: 1

Related Questions