I am trying to plot some data with the following code
from sklearn.datasets import make_blobs
import seaborn as sns
import numpy as np
X, y = make_blobs(n_samples=1000, n_features=2, centers=10, cluster_std=1.0, center_box=(-10.0, 10.0), shuffle=True, random_state=None)
palette = np.array(sns.color_palette("bright", 10)) #Chossing color
sns.scatterplot(X[:,0],X[:,1],legend='full',c=palette[y])
The color is beautiful, but the legend is missing.
When I check the documentation, I see:
How to draw the legend. If “brief”, numeric hue and size variables
....
So it seems I also need to include the hue argument.
But when I try the hue argument with the following codes, the following graph is created instead...
sns.scatterplot(X[:,0],X[:,1],legend='full',hue=y,c=palette[y])
The legend is showing, but the color is not what I want. After adding the hue argument, it seems it overwrite the palette argument. No matter what palette I choose, the color is still ugly as hell...
My question is:
How to show legend while maintaining the color that I want?
You would need to use the palette kwarg, and specify the hues with your y values.
from sklearn.datasets import make_blobs
import seaborn as sns
import matplotlib.pyplot as plt
X, y = make_blobs(n_samples=1000, n_features=2, centers=10, cluster_std=1.0,
center_box=(-10.0, 10.0), shuffle=True, random_state=None)
palette = sns.color_palette("bright", 10) #Choosing color
sns.scatterplot(X[:, 0], X[:, 1], palette=palette, hue=y, legend='full')
plt.show()
Related
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.
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()
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({'y':['a','b','c','d','e','f','g','h','i']\
,'x':[10,9,9,8,7,6,10,6,7]})
df.sort_values(by='x',inplace=True,ascending = True)
plt.barh(bottom=list(range(1,10)), width=df.x, height = 0.15, align='center',color = 'blue')
plt.xlim([0,11])
plt.yticks(list(range(1,10)),skills.y)
plt.show()
This code gives me a horizontal bar graph.
I want to add a circular dot at the edge of each bars.
Can someone please help me with that.
Tableau graph
I did this in tableau, I want to replicate the same in python.
Also, please let me know if there a better way of coding the same.
I am using Anaconda Python 3.5, Matplotlib library, Windows 10, Idlex IDE
You could just add a scatterplot on top of your bars, using matplotlib scatter function.
Also, note that you could use the numpy.arange function to generate your x values, instead of your current list(range(1,10)).
See example below
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame({'y':['a','b','c','d','e','f','g','h','i'],
'x':[10,9,9,8,7,6,10,6,7]})
df.sort_values(by='x',inplace=True,ascending = True)
plt.barh(bottom=np.arange(len(df)), width=df.x, height = 0.15, align='center',color = 'blue')
plt.scatter(df.x.values, y=np.arange(df.shape[0]), color='b', s=40)
plt.xlim([0,11])
plt.yticks(np.arange(len(df)),df.y)
plt.show()
AFAIK Mayavi does not come with any perceptually uniform colormaps. I tried naively to just pass it one of Matplotlib's colormaps but it failed:
from mayavi import mlab
import multiprocessing
import matplotlib.pyplot as plt
plasma = plt.get_cmap('plasma')
...
mlab.pipeline.volume(..., colormap=plasma)
TraitError: Cannot set the undefined 'colormap' attribute of a 'VolumeFactory' object.
Edit: I found a guide to convert Matplotlib colormaps to Mayavi colormaps. However, it unfortunately doesn't work since I am trying to use a volume using a perceptually uniform colormap.
from matplotlib.cm import get_cmap
import numpy as np
from mayavi import mlab
values = np.linspace(0., 1., 256)
lut_dict = {}
lut_dict['plasma'] = get_cmap('plasma')(values.copy())
x, y, z = np.ogrid[-10:10:20j, -10:10:20j, -10:10:20j]
s = np.sin(x*y*z)/(x*y*z)
mlab.pipeline.volume(mlab.pipeline.scalar_field(s), vmin=0, vmax=0.8, colormap=lut_dict['plasma']) # still getting the same error
mlab.axes()
mlab.show()
...
Instead of setting it as the colormap argument, if you set it as the ColorTransferFunction of the volume, it works as expected.
import numpy as np
from mayavi import mlab
from tvtk.util import ctf
from matplotlib.pyplot import cm
values = np.linspace(0., 1., 256)
x, y, z = np.ogrid[-10:10:20j, -10:10:20j, -10:10:20j]
s = np.sin(x*y*z)/(x*y*z)
volume = mlab.pipeline.volume(mlab.pipeline.scalar_field(s), vmin=0, vmax=0.8)
# save the existing colormap
c = ctf.save_ctfs(volume._volume_property)
# change it with the colors of the new colormap
# in this case 'plasma'
c['rgb']=cm.get_cmap('plasma')(values.copy())
# load the color transfer function to the volume
ctf.load_ctfs(c, volume._volume_property)
# signal for update
volume.update_ctf = True
mlab.show()
While the previous answer by like444 helped me partially with a similar problem, it leads to incorrect translation between colormaps. This is because the format in which matplotlib and tvtk store color information is slightly different: Matplotlib uses RGBA, while ColorTransferFunction uses VRGB, where V is the value in the shown data that this part of the colormap is assigned to. So by doing a 1-to-1 copy, green becomes red, blue becomes green and alpha becomes blue. The following code snippet fixes that:
def cmap_to_ctf(cmap_name):
values = list(np.linspace(0, 1, 256))
cmap = cm.get_cmap(cmap_name)(values)
transfer_function = ctf.ColorTransferFunction()
for i, v in enumerate(values):
transfer_function.add_rgb_point(v, cmap[i, 0], cmap[i, 1], cmap[i, 2])
return transfer_function
I am quite used to working with matlab and now trying to make the shift matplotlib and numpy. Is there a way in matplotlib that an image you are plotting occupies the whole figure window.
import numpy as np
import matplotlib.pyplot as plt
# get image im as nparray
# ........
plt.figure()
plt.imshow(im)
plt.set_cmap('hot')
plt.savefig("frame.png")
I want the image to maintain its aspect ratio and scale to the size of the figure ... so when I do savefig it exactly the same size as the input figure, and it is completely covered by the image.
Thanks.
I did this using the following snippet.
#!/usr/bin/env python
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
from pylab import *
delta = 0.025
x = y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = Z2-Z1 # difference of Gaussians
ax = Axes(plt.gcf(),[0,0,1,1],yticks=[],xticks=[],frame_on=False)
plt.gcf().delaxes(plt.gca())
plt.gcf().add_axes(ax)
im = plt.imshow(Z, cmap=cm.gray)
plt.show()
Note the grey border on the sides is related to the aspect rario of the Axes which is altered by setting aspect='equal', or aspect='auto' or your ratio.
Also as mentioned by Zhenya in the comments Similar StackOverflow Question
mentions the parameters to savefig of bbox_inches='tight' and pad_inches=-1 or pad_inches=0
You can use a function like the one below.
It calculates the needed size for the figure (in inches) according to the resolution in dpi you want.
import numpy as np
import matplotlib.pyplot as plt
def plot_im(image, dpi=80):
px,py = im.shape # depending of your matplotlib.rc you may
have to use py,px instead
#px,py = im[:,:,0].shape # if image has a (x,y,z) shape
size = (py/np.float(dpi), px/np.float(dpi)) # note the np.float()
fig = plt.figure(figsize=size, dpi=dpi)
ax = fig.add_axes([0, 0, 1, 1])
# Customize the axis
# remove top and right spines
ax.spines['right'].set_color('none')
ax.spines['left'].set_color('none')
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
# turn off ticks
ax.xaxis.set_ticks_position('none')
ax.yaxis.set_ticks_position('none')
ax.xaxis.set_ticklabels([])
ax.yaxis.set_ticklabels([])
ax.imshow(im)
plt.show()
Here's a minimal object-oriented solution:
fig = plt.figure(figsize=(8, 8))
ax = fig.add_axes([0, 0, 1, 1], frameon=False, xticks=[], yticks=[])
Testing it out with
ax.imshow([[0]])
fig.savefig('test.png')
saves out a uniform purple block.
edit: As #duhaime points out below, this requires the figure to have the same aspect as the axes.
If you'd like the axes to resize to the figure, add aspect='auto' to imshow.
If you'd like the figure to resize to be resized to the axes, add
from matplotlib import tight_bbox
bbox = fig.get_tightbbox(fig.canvas.get_renderer())
tight_bbox.adjust_bbox(fig, bbox, fig.canvas.fixed_dpi)
after the imshow call. This is the important bit of matplotlib's tight_layout functionality which is implicitly called by things like Jupyter's renderer.