matplotlib pyplot pcolor savefig colorbar transparency - matplotlib

I am trying to export a pcolor figure with a colorbar.
The cmap of the colorbar has a transparent color.
The exported figure has transparent colors in the axes but not in the colorbar. How can I fix this?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
x = np.random.random((10, 10))
colors = [(0,0,0,0), (0,0,0,1)]
cm = LinearSegmentedColormap.from_list('custom', colors, N=256, gamma=0)
plt.pcolor(x,cmap=cm)
plt.colorbar()
plt.savefig('figure.pdf',transparent=True)
I put the image against a grey background to check. As can be seen, the cmap in the axes is transparent while the one in the colorbar is not.

While the colorbar resides inside an axes, it has an additional background patch associated with it. This is white by default and will not be taken into account when transparent=True is used inside of savefig.
A solution is hence to remove the facecolor of this patch manually,
cb.patch.set_facecolor("none")
A complete example, which shows this without actually saving the figure
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
x = np.random.random((10, 10))
colors = [(1,1,1,0), (0,0,0,1)]
cm = LinearSegmentedColormap.from_list('custom', colors, N=256, gamma=0)
fig, ax = plt.subplots(facecolor="grey")
im = ax.pcolor(x,cmap=cm)
cb = fig.colorbar(im, drawedges=False)
ax.set_facecolor("none")
cb.patch.set_facecolor("none")
plt.show()

Related

Is it possible to achieve a continuous color gradient with surface plot using matplotlib?

I am trying to visualise the pixel intensity of a photo by plotting a 3D graph. In the code below, lab is an image I want to analyse. The code will look at the pixel intensity of every pixels in the image and plot a graph, where the height denotes the pixel intensity.
Here is a portion of my code:
import cv2
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from skimage import io, color
import glob
from PIL import Image
plt.figure(dpi=1200)
ax = plt.axes(projection='3d')
y = range(lab.shape[0])
x = range(lab.shape[1])
X, Y = np.meshgrid(x, y)
ax.view_init(elev=60., azim=60)
thickness = ax.plot_surface(
X,
Y,
lab[:, :, 0], # change value here to adjust the height
cmap=cm.coolwarm,
antialiased=False)
# Add a color bar which maps values to colors.
fig.colorbar(thickness, shrink=0.5, aspect=5)
It outputs:
As you can see, the colour gradient is not continuous despite the graph having many fine details and slight fluctuations in height which is not represented by the color map.
Is it possible to achieve a continuous color gradient with surface plot using matplotlib like the image below?
Thank you.
You can use the colormap hsv to get the same result.
import cv2
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from skimage import io, color
import glob
from PIL import Image
lab = cv2.imread('Lenna.png')
lab = cv2.cvtColor(lab, cv2.COLOR_BGR2LAB)
fig = plt.figure()
ax = plt.axes(projection='3d')
y = range(lab.shape[0])
x = range(lab.shape[1])
X, Y = np.meshgrid(x, y)
ax.view_init(elev=60., azim=60)
thickness = ax.plot_surface(
X,
Y,
lab[:, :, 0], # change value here to adjust the height
cmap=plt.get_cmap('hsv'),
antialiased=False)
# Add a color bar which maps values to colors.
fig.colorbar(thickness, shrink=0.5, aspect=5)
plt.show()
output :
Take a look at the documentation for more colormaps.

In Matplotlib, adding `trantsform` breaks rectangles [duplicate]

I wanted to rotate a Rectangle in matplotlib but when I apply the transformation, the rectangle doesn't show anymore:
rect = mpl.patches.Rectangle((0.0120,0),0.1,1000)
t = mpl.transforms.Affine2D().rotate_deg(45)
rect.set_transform(t)
is this a known bug or do I make a mistake?
The patch in the provided code makes it hard to tell what's going on, so I've made a clear demonstration that I worked out from a matplotlib example:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot(111)
r1 = patches.Rectangle((0,0), 20, 40, color="blue", alpha=0.50)
r2 = patches.Rectangle((0,0), 20, 40, color="red", alpha=0.50)
t2 = mpl.transforms.Affine2D().rotate_deg(-45) + ax.transData
r2.set_transform(t2)
ax.add_patch(r1)
ax.add_patch(r2)
plt.xlim(-20, 60)
plt.ylim(-20, 60)
plt.grid(True)
plt.show()
Apparently the transforms on patches are composites of several transforms for dealing with scaling and the bounding box. Adding the transform to the existing plot transform seems to give something more like what you'd expect. Though it looks like there's still an offset to work out.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot(111)
rect = patches.Rectangle((0.0120,0),0.1,1000)
t_start = ax.transData
t = mpl.transforms.Affine2D().rotate_deg(-45)
t_end = t_start + t
rect.set_transform(t_end)
print repr(t_start)
print repr(t_end)
ax.add_patch(rect)
plt.show()

how to customize color legend when using for loop in matplotlib, scatter

I want to draw a 3D scatter, in which the data is colored by group. Here is the data sample:
aa=pd.DataFrame({'a':[1,2,3,4,5],
'b':[2,3,4,5,6],
'c':[1,3,4,6,9],
'd':[0,0,1,2,3],
'e':['abc','sdf','ert','hgf','nhkm']})
Here, a, b, c are axis x, y, z. e is the text shown in the scatter. I need d to group the data and show different colors.
Here is my code:
fig = plt.figure()
ax = fig.gca(projection='3d')
zdirs = aa.loc[:,'e'].__array__()
xs = aa.loc[:,'a'].__array__()
ys = aa.loc[:,'b'].__array__()
zs = aa.loc[:,'c'].__array__()
colors = aa.loc[:,'d'].__array__()
colors1=np.where(colors==0,'grey',
np.where(colors==1,'yellow',
np.where(colors==2,'green',
np.where(colors==3,'pink','red'))))
for i in range(len(zdirs)): #plot each point + it's index as text above
ax.scatter(xs[i],ys[i],zs[i],color=colors1[i])
ax.text(xs[i],ys[i],zs[i], '%s' % (str(zdirs[i])), size=10, zorder=1, color='k')
ax.set_xlabel('a')
ax.set_ylabel('b')
ax.set_zlabel('c')
plt.show()
But I do not know how to put a legend on the plot. I hope my legend is like:
The colors and the numbers should match and be ordered.
Could anyone help me with how to customize the color bar?
First of all, I've taken the liberty to reduce your code a bit:
I'd suggest to create a ListedColormap to map integer->color, which allows you to pass the color column via c=aa['d'] (note it's c=, not color=!)
you don't need to use __array__() here, in the code below you can directly use aa['a']
finally, you can add an empty scatter plot for each color in the ListedColormap, and this can then be rendered correctly by ax.legend()
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib.colors import ListedColormap
import matplotlib.patches as mpatches
aa=pd.DataFrame({'a':[1,2,3,4,5],
'b':[2,3,4,5,6],
'c':[1,3,4,6,9],
'd':[0,0,1,2,3],
'e':['abc','sdf','ert','hgf','nhkm']})
fig = plt.figure()
ax = fig.gca(projection='3d')
cmap = ListedColormap(['grey', 'yellow', 'green', 'pink','red'])
ax.scatter(aa['a'],aa['b'],aa['c'],c=aa['d'],cmap=cmap)
for x,y,z,label in zip(aa['a'],aa['b'],aa['c'],aa['e']):
ax.text(x,y,z,label,size=10,zorder=1)
# Create a legend through an *empty* scatter plot
[ax.scatter([], [], c=cmap(i), label=str(i)) for i in range(len(aa))]
ax.legend()
ax.set_xlabel('a')
ax.set_ylabel('b')
ax.set_zlabel('c')
plt.show()

matplotlib: shorten a colorbar by half when the colorbar is created using axes_grid1

I am trying to shorten a colorbar by half. Does anyone know how to do this? I tried cax.get_position() and then cax.set_position(), but this method did not work.
Besides, it seems that axes created by axes_grid1 has the same bbox positions as the original axes. Is this a bug?
PS. I have to use axes_grid1 to create colorbar axes, because I need to use tight_layout() afterwards, and tight_layout() only applies to axes created by axes_grid1 but not ones created by add_axes().
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)))
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
bbox1 = ax.get_position()
print(bbox1)
bbox1 = cax.get_position()
print(bbox1)
plt.colorbar(im, cax=cax)
plt.show()
The whole point of the axes_divider is to divide the axes to make space for a new axes. This ensures that all axes have the same surrounding box. And that is the box you see being printed.
Some of the usual ways to create a colorbar, at a certain location in the figue are shown in this question. Here the problem seems to be to be able to call tight_layout. This is achievable with the following two options. (There might be others still.)
A. using gridspec
I'm not too sure about the exact requirements here, but it seems that using a normal grid layout would be more in the direction of what you need here.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, width_ratios=[95,5],)
ax = fig.add_subplot(gs[:, 0])
im = ax.imshow(np.arange(100).reshape((10,10)))
cax = fig.add_subplot(gs[1, 1])
fig.colorbar(im, cax=cax, ax=ax)
plt.tight_layout()
plt.show()
B. Using axes_grid1
If you really need to use axes_grid1, it might become a little bit more complicated.
import matplotlib.pyplot as plt
import matplotlib.axes
from mpl_toolkits.axes_grid1 import make_axes_locatable, Size
import numpy as np
fig, ax = plt.subplots()
im = ax.imshow(np.arange(100).reshape((10,10)))
divider = make_axes_locatable(ax)
pad = 0.03
pad_size = Size.Fraction(pad, Size.AxesY(ax))
xsize = Size.Fraction(0.05, Size.AxesX(ax))
ysize = Size.Fraction(0.5-pad/2., Size.AxesY(ax))
divider.set_horizontal([Size.AxesX(ax), pad_size, xsize])
divider.set_vertical([ysize, pad_size, ysize])
ax.set_axes_locator(divider.new_locator(0, 0, ny1=-1))
cax = matplotlib.axes.Axes(ax.get_figure(),
ax.get_position(original=True))
locator = divider.new_locator(nx=2, ny=0)
cax.set_axes_locator(locator)
fig.add_axes(cax)
fig.colorbar(im, cax=cax)
plt.tight_layout()
plt.show()

Matplotlib Color Palette

Is it possible to change what colors Matplotlib cycles through when it is generating its own colors for a graph's lines? I'm using the pylab module.
from pylab import *
import matplotlib.cm as cm
x=[1,2,3,4]
y=[5,6,7,8]
fig1 = Figure()
plot1 = fig1.add_subplot(311)
plot1.plot(x,y)
plot2 = fig1.add_subplot(312)
plot2.plot(x,y)
plot3 = fig1.add_subplot(313)
plot3.plot(x,y)
Yes, of course. Since it accept many kinds of color definition. It's easy to define your own color map. Here I just get colors from the colormap hot
import pylab as py
import numpy as np
import matplotlib.cm as cm
a = np.arange(0,10)
py.figure()
for i in np.arange(10):
c = cm.hot(i/10.,1)
py.plot(a,i*a,color=c)
py.show()
The colors are extracted from color maps. You can use one of the predefined colormaps, or define your own.
Unfortunately there is no way to use multiple colormaps per figure, you have to do it manually:
import pylab as pl
import matplotlib.cm as cm
xval = pl.arange(0, 20, 0.2)
pl.subplot(311)
pl.plot(xval, pl.sin(xval), c=cm.summer(0))
pl.subplot(312)
pl.plot(xval, pl.cos(xval), c=cm.spring(0))
pl.subplot(313)
pl.plot(xval, pl.arctan(xval), xval, pl.fabs(xval))
pl.show()