Create symmetric figures when using matplotlib labels - python

I am using plt.subplots with both ax.set_ylabel and fig.supylabel. However, this creates figures that are off-centered.
Is it possible to automatically increase the right margin such that the red line is at the center of the figure?
In the case I am doing this manually, how can I precisely measure by how much I should increase the right margin?

How about this:
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)
x = np.arange(50)
ax1.plot(x,np.sin(x))
ax2.plot(x,np.sin(x))
ax1.set_ylim(-1,1)
ax2.set_ylim(-1,1)
ax2.set_yticklabels('')
ax1.set_title('damped')
ax2.set_title('undamped')
ax1.set_ylabel('amplitude')
fig.suptitle('Different types of oscillations')
Output:
---edit---
Try this:
import matplotlib.gridspec as grd
fig = plt.subplots()
gs = grd.GridSpec(1, 2, wspace=0.5)
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
x = np.arange(50)
ax1.plot(x,np.sin(x))
ax2.plot(x,np.sin(x))
ax1.set_title('damped')
ax2.set_title('undamped')
ax1.set_ylabel('amplitude')
The keypoint is gs = grd.GridSpec(1, 2, wspace=0.5). Adjust wspace as you like. The plot below is for wspace=0.5

Related

Putting one color bar for several subplots from different dataframes

I looked everywhere and nothing really helped.
Here is my code:
fig = plt.figure(figsize=(12, 6))
marker_colors = pca_data2['Frame']
fig.suptitle('PCA')
plt.subplot(1, 2, 1)
x = pca_data2.PC_1
y = pca_data2.PC_2
plt.scatter(x, y, c = marker_colors, cmap = "inferno")
plt.colorbar()
plt.subplot(1, 2, 2)
x1 = pca_data.PC_1
y1 = pca_data.PC_2
plt.scatter(x1, y1, c = marker_colors, cmap = "inferno")
plt.colorbar()
plt.show()
pca_data and pca_data2 are two completely different dataframes from to completele different things. But I need them side by side with the 1 color bar being on the right side for all.
Thats how the figure looks like
When I try to remove the first plt.colorbar() then the two subplots look uneven.
I would really appreciate the help.
... since none of the answers seems to mention the fact that you can tell the colorbar the axes on which it should be drawn... here's a simple example how I would do it:
The benefits of this are:
it's much clearer to read
you have complete control over the size of the colorbar
you can extend this easily to any grid of subplots and any position of the colorbar
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
# generate some data
data, data1 = np.random.rand(10,10), np.random.rand(10,10)
x, y = np.meshgrid(np.linspace(0,1,10), np.linspace(0,1,10))
# initialize a plot-grid with 3 axes (2 plots and 1 colorbar)
gs = GridSpec(1, 3, width_ratios=[.48,.48,.04])
# set vmin and vmax explicitly to ensure that both colorbars have the same range!
vmin = np.min([np.min(data), np.min(data1)])
vmax = np.max([np.max(data), np.max(data1)])
plot_kwargs = dict(cmap = "inferno", vmin=vmin, vmax=vmax)
fig = plt.figure(figsize=(12, 6))
ax_0 = fig.add_subplot(gs[0], aspect='equal')
ax_1 = fig.add_subplot(gs[1], aspect='equal')
ax_cb = fig.add_subplot(gs[2])
s1 = ax_0.scatter(x, y, c = data, **plot_kwargs)
s2 = ax_1.scatter(x, y, c = data1, **plot_kwargs)
plt.colorbar(s1, cax=ax_cb)
You can use aspect to set a fixed aspect ratio on the subplots. Then append the colorbars to the right side of each axis and discard the first colorbar, to get an even layout:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig = plt.figure(figsize=(12, 6))
marker_colors = range(0,10)
x = x1 = np.random.randint(0,10,10)
y = y1 = np.random.randint(0,10,10)
ax1 = fig.add_subplot(1, 2, 1, aspect="equal") # or e.g. aspect=0.9
g1 = ax1.scatter(x, y, c = marker_colors, cmap = "inferno", )
ax2 = fig.add_subplot(1, 2, 2, aspect="equal") # or e.g. aspect=0.9
g2 = ax2.scatter(x1, y1, c = marker_colors, cmap = "inferno")
# put colorbars right next to axes
divider1 = make_axes_locatable(ax1)
cax1 = divider1.append_axes("right", size="5%", pad=0.05)
divider2 = make_axes_locatable(ax2)
cax2 = divider2.append_axes("right", size="5%", pad=0.05)
# reserve space for 1st colorbar, then remove
cbar1 = fig.colorbar(g1, cax=cax1)
fig.delaxes(fig.axes[2])
# 2nd colorbar
cbar2 = fig.colorbar(g2, cax=cax2)
plt.tight_layout()
plt.show()
If you want a different aspect ratio, you can modify aspect, e.g. to aspect=0.9. The result will have locked aspect ratios for the subplots, even if you resize the figure box:
use following code:
Hope it will match your problem statment.
fig = plt.figure(figsize=(12, 6))
marker_colors = range(0,10)
x=x1=np.random.randint(0,10,10)
y=y1=np.random.randint(0,10,10)
plt.subplot(1, 2, 1)
g1=plt.scatter(x, y, c = marker_colors, cmap = "inferno")
plt.subplot(1, 2, 2)
g2=plt.scatter(x1, y1, c = marker_colors, cmap = "inferno")
g11=plt.colorbar(g1)
g12=plt.colorbar(g2)
g11.ax.set_title('g1')
g12.ax.set_title('g2')

Creating a 2x2 subplot from one dataset as different graphs

I have a large census dataset I am working with and am taking different data from it and representing it as a singular .png in the end. I have created the graphs individually, but when I try to add them to the subplots they get distorted or axis get messed up.
Current code:
fig = plt.figure()
ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 3)
ax4 = fig.add_subplot(2, 2, 4)
ax1.pie(df.data.valuecounts(normalize=True),labels=None,startangle-240)
ax1.legend(['a','b','c','d','e'])
ax1.axis('equal')
data2=df[['A']].dropna().values
kde=df.A.plot.kde()
binss = np.logspace(0.01,7.0)
ax2=plt.hist(hincp, normed=True, bins=binss)
ax2=plt.xscale('log')
ax3 = df.replace(np.nan,0)
ax3 = (df.groupby(['G'])['R'].sum()/1000)
ax3.plot.bar(width=0.9, color='red',title='Gs').set_ylabel('Rs')
ax3.set_ylabel('Rs')
ax3.set_xlabel('# G')
t = df[['p','o','s','y']]
ax4=plt.scatter(t.o,t.p,s=t.s,c=t.y, marker = 'o', alpha = 0.2)
plt.ylim(0, 10000)
plt.xlim(0,1200000)
cbar=plt.colorbar()
plt.title("this vs that", loc = 'center')
plt.xlabel('this')
plt.ylabel('that')
All four types of graphs should be displayed and not overlap.
You create Axes for each subplot but then you don't use them.
ax1.pie(...) looks correct but later you don't use ax2,ax3,ax4.
If you are going to to use the DataFrame plotting methods, just call plt.subplot before each new plot. Like this.
df = pd.DataFrame(np.random.random((6,3)))
plt.subplot(3,1,1)
df.loc[:,0].plot()
plt.subplot(3,1,2)
df.loc[:,1].plot()
plt.subplot(3,1,3)
df.loc[:,2].plot()
plt.show()
plt.close()
Or use the Axes that you create.
df = pd.DataFrame(np.random.random((6,3)))
fig = plt.figure()
ax1 = fig.add_subplot(3,1,1)
ax2 = fig.add_subplot(3,1,2)
ax3 = fig.add_subplot(3,1,3)
ax1.plot(df.loc[:,0])
ax2.plot(df.loc[:,1])
ax3.plot(df.loc[:,2])
plt.show()
plt.close()

How to adjust columns widths with gridspec?

How can I fix this plot?
I want:
both color bars not overlap.
make their height equal to the plot.
Here is my code:
combined = (...) # some irrelevant to question data praparation - this variable contain square matrix with RGBA chanels
plt.figure(dpi=300, figsize=(2.1,1.9))
gs = gridspec.GridSpec(1, 3, width_ratios=[20,1,1])
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
ax3 = plt.subplot(gs[2])
cax = ax1.imshow(combined, interpolation="None")
mpl.colorbar.ColorbarBase(ax2, cmap=cmap_top, norm=norm_top)
mpl.colorbar.ColorbarBase(ax3, cmap=cmap_top, norm=norm_top)
I'm using python 3.6 and matplotlib 2.0.
I would consider two possibilities for problem number 1:
a. Modify the wspace parameter that controls horizontal space between figures i.e. :
gs = gridspec.GridSpec(1, 3, width_ratios=[20,1,1])
gs.update(wspace=0.05)
b. Add an extra column between the first and second colorbar that acts as some void space:
gs = gridspec.GridSpec(1, 4, width_ratios=[20,1,0.15,1])
As for problem number 2, I would write it differently:
ax2=plt.subplot(gs[0,1] )
cb1 = matplotlib.colorbar.ColorbarBase(ax2, cmap="RdBu_r")
Hope it helps!
A suggestion would be not to use gridspec in this case. You can create new colorbar axes by using the make_axes_locatable class from the mpl_toolkits.axes_grid1.
You would then need to find some fitting parameters for the padding of the divider, as well as for the figure margins (using subplots_adjust).
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.colorbar
import numpy as np; np.random.seed(1)
a = -np.log10(np.random.rand(25,25))
fig, ax = plt.subplots(dpi=300, figsize=(2.1,1.9))
fig.subplots_adjust(left=0.15,right=.78)
cmap=plt.cm.terrain
norm = matplotlib.colors.LogNorm(1e-3, 4)
im = ax.imshow(a, interpolation="None", cmap=cmap, norm=norm)
divider = make_axes_locatable(ax)
cax = divider.new_horizontal(size="5%", pad=0.05)
cax2 = divider.new_horizontal(size="5%", pad=0.45)
fig.add_axes(cax)
fig.add_axes(cax2)
plt.colorbar(im, cax=cax)
plt.colorbar(im, cax=cax2)
plt.show()
Making enough space such that the colorbar ticklabels don't overlap takes in this case almost half the figure width, but I suppose this is how you want it.

Colorbar sticking to axes

I've got a small problem with the positioning of a colorbar using matplotlib. I'm plotting several subplots and one of them is an image. I want this image to have a colorbar but I want it to be "stuck" to the figure, so that there is no space between the two axes (the one from the figure and the one from the colorbar). Even if the figure is resized, the colorbar should always stick to the image axes.
PS - I don't mind if ax3 (the axes of my image) is deformed.
Here's what I've got for the moment:
# Imports
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from scipy import *
# Generating data
data = (rand(2048,2048), rand(2048,2048)+1000)
colorplot = "blue"
metadata = ("Test1", "Test2", "spectral")
# Generating figure and subplots
fig = plt.figure()
fig.subplots_adjust(right = 0.8)
gs1 = gridspec.GridSpec(3, 5)
gs1.update(left=0.05,\
right=0.95,\
top=0.95,\
bottom=0.05,\
wspace=0.2,\
hspace=0.05)
ax1 = fig.add_subplot(gs1[0,0])
ax2 = fig.add_subplot(gs1[0,1])
ax3 = fig.add_subplot(gs1[1:3,0:2])
ax4 = fig.add_subplot(gs1[:,2:])
list_axes = [ax1, ax2, ax3, ax4]
for i in list_axes:
i.autoscale_view(tight=False, scalex=False, scaley=True)
# Misc computation
array = data[1]-data[0]
mean_value = np.mean(array)
std_value = np.std(array)
nb_sigma = 5
ax1.imshow(data[0], interpolation = "nearest", cmap = metadata[2])
ax2.imshow(data[1], interpolation = "nearest", cmap = metadata[2])
im = ax3.imshow(array, vmin = np.min(array[array>mean_value-nb_sigma*std_value]), vmax = np.max(array[array<mean_value+nb_sigma*std_value]), interpolation = "nearest", cmap = metadata[2])
ax3.set_adjustable('box-forced')
# Creating axes for the colorbar
axes_cb = fig.add_axes([ax3.get_position().bounds[0],ax3.get_position().bounds[1], ax3.get_position().bounds[2], 0.05])
fig.colorbar(im, cax = axes_cb, orientation = 'horizontal')
axes_cb.yaxis.tick_left()
n, bins, patches = ax4.hist(array.flatten(), color = colorplot, bins = 50, normed = True)
plt.show()
Thank you!

Matplotlib: Plotting the same graph in two different figures without writting the "plot(x,y)" line twice

I have this simple code that plots exactly the same thing in two different figures (fig1 and fig2). However, I have to write the line ax?.plot(x, y) twice, once for ax1 and once for ax2. How can I have only one plot expression (having multiple redondant ones could be a source of troubles for my more complex code). Something like ax1,ax2.plot(x, y) ... ?
import numpy as np
import matplotlib.pyplot as plt
#Prepares the data
x = np.arange(5)
y = np.exp(x)
#plot fig1
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
#plot fig2
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
#adds the same fig2 plot on fig1
ax1.plot(x, y)
ax2.plot(x, y)
plt.show()
You can either add each axes to a list, like this:
import numpy as np
import matplotlib.pyplot as plt
axes_lst = []
#Prepares the data
x = np.arange(5)
y = np.exp(x)
#plot fig1
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
axes_lst.append(ax1)
#plot fig2
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
axes_lst.append(ax2)
for ax in axes_lst:
ax.plot(x, y)
plt.show()
or you can use this unsupported feature to pull all of the figures in pyplot. Taken from https://stackoverflow.com/a/3783303/1269969
figures=[manager.canvas.figure
for manager in matplotlib._pylab_helpers.Gcf.get_all_fig_managers()]
for figure in figures:
figure.gca().plot(x,y)
Without knowing about matplotlib, you could add all your axes (?) to a list:
to_plot = []
to_plot.append(ax1)
...
to_plot.append(ax2)
...
# apply the same action to each ax
for ax in to_plot:
ax.plot(x, y)
You could then add as many as you like, and the same thing will happen to each.

Categories