Matplotlib Axes3D Ratio Savefig - python

I have a little problem with matplotlib.
The size assignment is good when displaying (plt.show()) a 2D or 3D visualization.
But does not happen if it's a 3D visualization during the save (Fig.savefig(...))
The easiest way is to show the result.
Have you an Idea ?
FILES :
2DVisualisationFile
3DVisualisationFile
PYTHON SCRIPT
# coding: utf8
import os
import numpy as np
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 unused import
import matplotlib.pyplot as plt
DPI = 150
FIG_SIZE = (8.60, 5.40)
mu = 1
sigma = 0.75
S = np.random.normal(mu, sigma, size=(1000,3))
# 2D Visualisation
Fig = plt.figure(figsize = FIG_SIZE, dpi = DPI)
ax = Fig.add_subplot(111)
ax.scatter(S[:,0], S[:,1], alpha=0.5)
print(Fig.get_size_inches())
plt.show()
Fig.savefig(os.path.dirname(__file__) + "/Samples_Test.png", transparent = False, bbox_inches = 'tight', dpi=DPI)
plt.close('all')
# 3D Visualisation
Fig = plt.figure(figsize = FIG_SIZE, dpi = DPI)
ax = Fig.add_subplot(111, projection='3d')
ax.scatter(S[:,0], S[:,1], S[:,2], alpha=0.5)
print(Fig.get_size_inches())
plt.show()
Fig.savefig(os.path.dirname(__file__) + "/Samples_Test2.png", transparent = False, bbox_inches = 'tight', dpi=DPI)
plt.close('all')

The problem is, that with bbox_inches = 'tight' the figure size can be changed during saving, see matplotlib.pyplot.savefig.
Instead use bbox_inches = None and the saved figure will have the correct size.
import matplotlib.pyplot as plt
FIG_SIZE = (6, 3)
fig = plt.figure(figsize = FIG_SIZE)
ax = fig.add_subplot(111, projection='3d')
ax.plot([0,1], [0,1], [0,1])
plt.show()
fig.savefig("bbox_inches_tight.png", bbox_inches = 'tight')
fig.savefig("bbox_inches_None.png", bbox_inches = None)
plt.close('all')

Related

colorbar changes the size of subplot in python

I use the following code to generate side-by-size images and I need to add colorbar only to the second image in the row. I use the following code for it
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.gridspec as gridspec
def plotting(x):
gs1 = gridspec.GridSpec(1, 2)
gs1.update(wspace=0.005, hspace=0.005)
plt.subplot(gs1[0])
plt.imshow(x)
plt.axis('off')
plt.title('dog')
ax1 = plt.subplot(gs1[1])
imc = plt.imshow(x, cmap='hot', interpolation='nearest')
plt.axis('off')
plt.title('dog')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(imc, cax=cax)
plt.tight_layout()
plt.show()
However it comes out the size of side-by-side images are not equal. I wonder how I could fix this issue?
You can use ImageGrid, which was created exactly for this purpose:
from mpl_toolkits.axes_grid1 import ImageGrid
x = np.random.random(size=(10,10))
fig = plt.figure()
grid = ImageGrid(fig, 111,
nrows_ncols = (1,2),
axes_pad = 0.05,
cbar_location = "right",
cbar_mode="single",
cbar_size="5%",
cbar_pad=0.05
)
grid[0].imshow(x)
grid[0].axis('off')
grid[0].set_title('dog')
imc = grid[1].imshow(x, cmap='hot', interpolation='nearest')
grid[1].axis('off')
grid[1].set_title('dog')
plt.colorbar(imc, cax=grid.cbar_axes[0])

How to set discrete colorbar ticks in mpl_toolkits.axes_grid1.ImageGrid?

I want to set discrete colorbar in ImageGrid.
ImageGrid
Here's an example:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
import numpy as np
import matplotlib
lon,lat = np.meshgrid(np.arange(-180, 180, 10), np.arange(-85, 90, 10))
data = np.sort(np.random.rand(18, 36),axis=1)
fig = plt.figure()
grid = ImageGrid(fig, 111,
nrows_ncols=(2, 1),
axes_pad=(0.35, 0.35),
label_mode="1",
share_all=True,
cbar_location="right",
cbar_mode="each",
cbar_size="5%",
cbar_pad="6%",
)
# Settings
bounds = [0,0.01,0.04,0.07,0.1,0.13,0.16,0.2,0.25,0.35,0.45,0.6,0.9]
colors = ['#390231','#7F1CAB','#0047FD','#0072FE','#019EFF','#00C4FF','#01EDFF',\
'#00FFFB','#00FFC8','#29F905','#FBDD03','#FA0F00']
# Original colorbar
p = grid[0].pcolormesh(lon,lat,data, vmin=0, vmax=0.9, cmap='jet')
cb = grid.cbar_axes[0].colorbar(p)
# Defined colorbar
cmap = matplotlib.colors.ListedColormap(colors)
norm = matplotlib.colors.BoundaryNorm(bounds, cmap.N)
p = grid[1].pcolormesh(lon,lat,data, cmap=cmap, norm=norm)
cb = grid.cbar_axes[1].colorbar(p, ticks=bounds)
grid[0].set_title('jet')
grid[1].set_title('Defined')
plt.show()
This is the result:
As you can see, the location of ticks are wrong.
If ticks are at boundaries of each color block, the second figure will look correct.
Subplots
Then, I tested subplots. It works fine!
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
lon,lat = np.meshgrid(np.arange(-180, 180, 10), np.arange(-85, 90, 10))
data = np.sort(np.random.rand(18, 36),axis=1)
f, (ax1, ax2) = plt.subplots(1, 2,sharey=True)
# Settings
bounds = [0,0.01,0.04,0.07,0.1,0.13,0.16,0.2,0.25,0.35,0.45,0.6,0.9]
colors = ['#390231','#7F1CAB','#0047FD','#0072FE','#019EFF','#00C4FF','#01EDFF',\
'#00FFFB','#00FFC8','#29F905','#FBDD03','#FA0F00']
# Defined colorbar
cmap = matplotlib.colors.ListedColormap(colors)
norm = matplotlib.colors.BoundaryNorm(bounds, cmap.N)
# Jet
p = ax1.pcolormesh(lon,lat,data, vmin=0, vmax=0.9, cmap='jet')
f.colorbar(p,ax=ax1)
ax1.set_title('jet')
# Defined
p = ax2.pcolormesh(lon,lat,data, cmap=cmap, norm=norm)
f.colorbar(p,ax=ax2,ticks=bounds)
ax2.set_title('defined')
plt.show()
This is the result:
Single
I tested my script in single figure. It works fine!
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
lon,lat = np.meshgrid(np.arange(-180, 180, 10), np.arange(-85, 90, 10))
data = np.sort(np.random.rand(18, 36),axis=1)
fig = plt.figure()
# Settings
bounds = [0,0.01,0.04,0.07,0.1,0.13,0.16,0.2,0.25,0.35,0.45,0.6,0.9]
colors = ['#390231','#7F1CAB','#0047FD','#0072FE','#019EFF','#00C4FF','#01EDFF',\
'#00FFFB','#00FFC8','#29F905','#FBDD03','#FA0F00']
# Defined colorbar
cmap = matplotlib.colors.ListedColormap(colors)
norm = matplotlib.colors.BoundaryNorm(bounds, cmap.N)
# Jet
plt.pcolormesh(lon,lat,data, vmin=0, vmax=0.9, cmap='jet')
plt.colorbar()
plt.show()
# Defined
p = plt.pcolormesh(lon,lat,data, cmap=cmap, norm=norm)
plt.colorbar(p, ticks=bounds)
plt.title('Single fig')
plt.show()
This is the result of single figure of jet and defined:
A workaround would be to set the labels manually.
ticks=np.linspace(bounds[0],bounds[-1], len(bounds))
cb = grid.cbar_axes[1].colorbar(p, ticks=ticks)
cb.ax.set_yticklabels(bounds)

Reduce horizontal colorbar padding

I'm trying to generate a plot with several axis, each one with their own colorbar (code below). If I use the default colorbar plotting I get too much horizontal spacing between the plot and the colorbar:
If I try to use the make_axes_locatable() method I get this horrible result:
What is going on and how can I fix this?
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.gridspec as gridspec
from mpl_toolkits.axes_grid1 import make_axes_locatable
# Random data to plot
data = np.random.uniform(0., 1., (2, 100))
z = np.random.uniform(0., 10., 100)
# Define figure
fig = plt.figure(figsize=(30, 30))
gs = gridspec.GridSpec(12, 12)
for i in range(2):
ax = plt.subplot(gs[2 * i:2 + (2 * i), 0:8])
SC = plt.scatter(*data, c=z)
# Colorbar 1
cbar = plt.colorbar()
# Colorbar 2
# the_divider = make_axes_locatable(ax)
# color_axis = the_divider.append_axes("right", size="1%", pad=0.)
# cbar = plt.colorbar(SC, cax=color_axis)
cbar.set_label("test", fontsize=15, labelpad=10)
fig.tight_layout()
plt.savefig('test.png', dpi=300, bbox_inches='tight')
Use the pad argument of colorbar to set the padding between the axes and the colorbar. pad is given in units of the fraction of the original axes' size to use as space. Here e.g. pad=0.01 might make sense.
import numpy as np
from matplotlib import pyplot as plt
# Random data to plot
data = np.random.uniform(0., 1., (2, 100))
z = np.random.uniform(0., 10., 100)
# Define figure
fig, axes = plt.subplots(nrows=2, figsize=(30, 30))
for i, ax in enumerate(axes.flat):
sc = ax.scatter(*data, c=z)
cbar = fig.colorbar(sc, ax=ax, pad=0.01)
cbar.set_label("test", fontsize=15, labelpad=10)
fig.tight_layout()
plt.savefig('test.png', dpi=300, bbox_inches='tight')

moving colorbar with gridspec

I am making a plot with multiple figures and corresponding colorbars. This page http://www.sc.eso.org/~bdias/pycoffee/codes/20160407/gridspec_demo.html claims to know the best way of doing so. I am inclined to believe them.
However, I have run into issues adressing the kwags of the colorbar when I do it their way:
from matplotlib.colorbar import Colorbar
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
import numpy as np
median = np.zeros((100,100))
map0 = np.zeros((100,100))
map1 = map0
map2 = map0
fig = plt.figure()
plt.tight_layout()
gs = gridspec.GridSpec(2,6)
ax = plt.subplot(gs[0,0])
cbax = plt.subplot(gs[0,1])
ax1 = plt.subplot(gs[0,2])
cbax1 = plt.subplot(gs[0,3])
ax2 = plt.subplot(gs[0,4])
cbax2 = plt.subplot(gs[0,5])
ax3 = plt.subplot(gs[1,0])
cbax3 = plt.subplot(gs[1,1])
ax4 = plt.subplot(gs[1,2])
cbax4 = plt.subplot(gs[1,3])
ax5 = plt.subplot(gs[1,4])
cbax5 = plt.subplot(gs[1,5])
cax = ax.imshow(map0)
ax.contour(median)
cb = Colorbar(ax = cbax,mappable = cax,shrink=0.8)
cax1 = ax1.imshow(map1)
ax1.contour(median)
cb1 = Colorbar(ax = cbax1,mappable = cax1)
cax2 = ax2.imshow(map2)
ax2.contour(median)
cb2 = Colorbar(ax = cbax2,mappable = cax2)
cax3 = ax3.imshow(map0/median)
ax3.contour(median)
cb3 = Colorbar(ax = cbax3,mappable = cax3)
cax4 = ax4.imshow(map1/median)
ax4.contour(median)
cb4 = Colorbar(ax = cbax4,mappable = cax4)
cax5 = ax5.imshow(map2)
ax5.contour(median)
cb5 = Colorbar(ax = cbax5,mappable = cax5)
When I now call the kwargs shrink and or pad I get the following message:
Traceback (most recent call last):
File "plot_integratedMaps.py", line 173, in <module>
main()
File "plot_integratedMaps.py", line 171, in main
plot_integratedMaps(map630,map869,mapTot,median)
File "plot_integratedMaps.py", line 129, in plot_integratedMaps
cb = Colorbar(ax = cbax,mappable = cax,shrink=0.8)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/colorbar.py", line 943, in __init__
ColorbarBase.__init__(self, ax, **kw)
TypeError: __init__() got an unexpected keyword argument 'shrink'
I guess it makes sense that I cant pad the colorbar in in the gs[0,1] and have to movegs[0,1] instead. But I don't get why shrink doesn't work?
am using Python 2.7.12
I would not consider it useful to create Colorbar directly like in the link; instead one could use fig.colorbar(). However, this is only tangential to the problem.
First consider creating a colorbar next to a plot.
import matplotlib.pyplot as plt
import numpy as np
median = np.zeros((100,100))
map0 = np.zeros((100,100))
fig, ax = plt.subplots()
im = ax.imshow(map0)
ax.contour(median)
cb = fig.colorbar(im, ax=ax, shrink=0.8)
plt.show()
Here, shrink works fine because you want the axes in which the colorbar resides to be a factor 0.8 smaller than the axes ax to which it belongs.
Now, if you specify the axes in which the colorbar should reside, shrink does not make any sense, because the axes does not need to be created inside the colorbar function, but you supply it externally.
import matplotlib.pyplot as plt
import numpy as np
median = np.zeros((100,100))
map0 = np.zeros((100,100))
fig, (ax,cax) = plt.subplots(ncols=2)
im = ax.imshow(map0)
ax.contour(median)
#using `shrink` here would produce an error,
# because the colorbar axes (cax) already exists
# instead of
# cb = fig.colorbar(im, cax=cax, shrink=0.8)
# you need
cb = fig.colorbar(im, cax=cax)
plt.show()
Note that this is independend of gridspec. Whether or not you want to use gridspec is also a question of taste, but surely not needed for simple plots.
If you have more plots, it again depends what you want to show. The edited example from the question looks more like a regular grid. Here creating a colorbar axes for each subplot could be efficiently done via make_axes_locatable.
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.pyplot as plt
import numpy as np
data = np.random.rand(6,6)
fig, axes = plt.subplots(nrows=2, ncols=3)
for ax in axes.flatten():
im = ax.imshow(data)
div = make_axes_locatable(ax)
cax = div.append_axes("right", size="5%", pad=0.1)
cbar = fig.colorbar(im, cax=cax)
plt.tight_layout()
plt.show()
Taking the above, you may shrink the colorbars by not using this axes divider, but as usual, create your colorbar and use the shrink argument.
import matplotlib.pyplot as plt
import numpy as np
data = np.random.rand(6,6)
fig, axes = plt.subplots(nrows=2, ncols=3)
for ax in axes.flatten():
im = ax.imshow(data)
cbar = fig.colorbar(im, ax=ax, shrink=0.4)
plt.tight_layout()
plt.show()

Colorbar tick labels as log outputs

I am playing around with histogram2d and I am trying incorporate a color bar logarithmic values.
Here is my current code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.colors import LinearSegmentedColormap
cmap = LinearSegmentedColormap.from_list('mycmap', ['black', 'maroon',
'crimson', 'orange', 'white'])
fig = plt.figure()
ax = fig.add_subplot(111)
H = ax.hist2d(gas_pos[:,0]/0.7, gas_pos[:,1]/0.7, cmap=cmap,
norm=matplotlib.colors.LogNorm(), bins=350, weights=np.log(gas_Temp))
ax.tick_params(axis=u'both', which=u'both',length=0)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
cb = fig.colorbar(H[3], ax=ax, shrink=0.8, pad=0.01,
orientation="horizontal", label=r'$\log T\ [\mathrm{K}]$')
cb.ax.set_xticklabels([1,2,3,4])
cb.update_ticks()
empty = Rectangle((0,0 ), 0, 0, alpha=0.0)
redshift = fig.legend([empty], [r'$z = 127$'],
loc='upper right', frameon=False, handlelength=0, handletextpad=0)
redshift.get_texts()[0].set_color('white')
#fig.add_artist(redshift)
plt.show()
The weights are values not passed through np.log() and are currently being normalized through LogNorm().
What I am trying to get is to have the colorbar tic labels to be the logarithmic values of what is currently there eg. 10**4 --> 4, 10**6 --> 6, etc.
I have tried changing the formatting and also passing through the logarithmic values of np.log(gas_Temp), but nothing is really working.
The idiomatic thing to do is use a LogFormatterExponent to do the formatting of your colorbar. That's exactly what you need: to display 10**x values as x, or in other words, to display y values as log10(x).
Proof using dummy data:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
from matplotlib.ticker import LogFormatterExponent # <-- one new import here
# generate dummy data
histdata = 10**(np.random.rand(200,200)*4 + 1) # 10^1 -> 10^5
# plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.tick_params(axis=u'both', which=u'both',length=0)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
im = plt.imshow(histdata,cmap='viridis',norm=LogNorm())
cb = fig.colorbar(im, ax=ax, shrink=0.8, pad=0.01,
orientation="horizontal", label=r'$\log T\ [\mathrm{K}]$')
# v-- one new line here
cb.formatter = LogFormatterExponent(base=10) # 10 is the default
cb.update_ticks()
Compare the result of your original (left) with the modified version (right):

Categories

Resources