I would like to fill in polygons with vertical gradient (white-to-red) using the .set_facecolor() method. I defined a colormap using matplotlib.colors.LinearSegmentedColormap but it seems I am not allowed to pass colormap directly to color setting methods like .set_facecolor(). If I merely pass one color, it runs successfully - how can I pass a gradient to have the intended behavior, with colors ranging from white bottom to red top?
Working snippet, with fix color:
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
from matplotlib import colors, patches
import numpy as np
fig,ax = plt.subplots(1)
patches = []
verts = np.random.rand(3,2)
polygon = Polygon(verts,closed=True)
patches.append(polygon)
collection = PatchCollection(patches)
ax.add_collection(collection)
collection.set_color("blue")
ax.autoscale_view()
plt.show()
Not working snippet with custom gradient:
cmap = colors.LinearSegmentedColormap.from_list('white_to_red', ['white', 'red'])
fig,ax = plt.subplots(1)
patches = []
verts = np.random.rand(3,2)
polygon = Polygon(verts,closed=True)
patches.append(polygon)
collection = PatchCollection(patches)
ax.add_collection(collection)
collection.set_facecolor(cmap)
ax.autoscale_view()
plt.show()
You can use:
ax.imshow to create an image with a gradient, localized to a specific region of the plot.
the set_clip_path method to mask the polygon-region over the image.
Like this:
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
from matplotlib import colors, patches
import matplotlib.cm as cm
import numpy as np
fig,ax = plt.subplots(1)
verts = np.random.rand(3, 2)
xmin, xmax = verts[:, 0].min(), verts[:, 0].max()
ymin, ymax = verts[:, 1].min(), verts[:, 1].max()
cmap = colors.LinearSegmentedColormap.from_list('white_to_red', ['white', 'red'])
grad = np.atleast_2d(np.linspace(0, 1, 256)).T
img = ax.imshow(np.flip(grad), extent=[xmin, xmax, ymin, ymax],interpolation='nearest', aspect='auto', cmap=cmap)
polygon = Polygon(verts, closed=True, facecolor='none', edgecolor='none')
ax.add_patch(polygon)
img.set_clip_path(polygon)
ax.autoscale_view()
plt.show()
Related
I've made a colormap from a matrix (matrix300.txt). I would like to normalize my colormap, but I don't know how to do it. The axes should be from 0 to 3.
import numpy as np
import matplotlib.pyplot as plt
import math
from matplotlib import colors
import matplotlib.colors as colors
p = np.loadtxt('matrix300.txt')
cmap = colors.ListedColormap(['yellow', 'white'], name='Gamma=1')
bounds = [-1, 0, 1]
norm = colors.BoundaryNorm(bounds, cmap.N)
img = plt.imshow(p, interpolation='nearest', origin='lower', cmap=cmap, norm=norm)
plt.colorbar(img, cmap=cmap, norm=norm, boundaries=bounds)
plt.xlabel("h_0")
plt.ylabel("h")
plt.show()
Your usage of ListedColormap is not right here. It is for creating a user-defined colormap. So it may be a bit too much of elaborating if you need a colormap just for plotting. I post an example using ListedColormap anyway.
import numpy as np
import matplotlib.pyplot as plt
import math
from matplotlib import colors
import matplotlib.colors as colors
# dummy data
yy, xx = np.mgrid[0:1:10j, 0:1:10j]
p = np.exp(-10*(xx-0.5)**2-10*(yy-0.5)**2) # gaussian function
# create your own colormap
pmax, pmin = np.max(p), np.min(p) # get data range
bounds = np.linspace(pmin, pmax, 100) # set data range for colormap
num = 100 # how many colors do you need?
norm = colors.BoundaryNorm(bounds, ncolors=num) # an object for cmap normalization
carray = np.array([np.linspace(0,1,num), np.linspace(0.0,0.25,num), [0.5]*num, [1]*num]).T # list of RGBA values
cmap = colors.ListedColormap(carray, N=100, name='mycolormap') # create your own color map from carray
# plot data
img = plt.imshow(p, interpolation='nearest', origin='lower', cmap=cmap, norm=norm)
plt.colorbar(img, cmap=cmap, norm=norm, boundaries=bounds)
plt.show()
Mush easier way is to use pcolormesh.
fig, ax = plt.subplots(1,1)
ax.set_aspect("equal")
im = ax.pcolormesh(xx, yy, p, vmin=pmin, vmax=pmax)
cbar = fig.colorbar(mappable=im)
plt.show()
When creating a matplotlib colorbar, it is possible to set drawedges to True which separates the colors of the colorbar with black lines. However, when the colorbar is extended using extend='both', the black lines at the extremities do not show up. Is that a bug? Is there a possibility to draw those edges otherwise?
Here is the code:
import matplotlib as mpl
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import from_levels_and_colors
my_cmap = mpl.cm.viridis
bounds = np.arange(10)
nb_colors = len(bounds) + 1
colors = my_cmap(np.linspace(100, 255, nb_colors).astype(int))
my_cmap, my_norm = from_levels_and_colors(bounds, colors, extend='both')
plt.figure(figsize=(5, 1))
ax = plt.subplot(111)
cbar = mpl.colorbar.ColorbarBase(ax, cmap=my_cmap, norm=my_norm, orientation='horizontal', drawedges=True)
plt.subplots_adjust(left=0.05, bottom=0.4, right=0.95, top=0.9)
plt.show()
and the figure it gives:
I looked into it from your question and found a way to change the color of the border and vertical lines of the color bar. I used that to change them to red. The result I got was that the extended outline was red, so my guess is that I just pulled the short sides of the normal color bar rectangle to the left and right.
I found this response helpful.
cbar.outline.set_edgecolor('red')
cbar.dividers.set_color('red')
So I think the only way to do this is to add vertical lines.
import matplotlib as mpl
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import from_levels_and_colors
my_cmap = mpl.cm.viridis
bounds = np.arange(10)
nb_colors = len(bounds) + 1
colors = my_cmap(np.linspace(100, 255, nb_colors).astype(int))
my_cmap, my_norm = from_levels_and_colors(bounds, colors, extend='both')
plt.figure(figsize=(6, 2))
ax = plt.subplot(111)
cbar = mpl.colorbar.ColorbarBase(ax, cmap=my_cmap, norm=my_norm, orientation='horizontal', drawedges=True)
# update
cbar.outline.set_edgecolor('red')
cbar.dividers.set_color('red')
plt.axvline(max(bounds), color='red', alpha=0.3, linewidth=3.5)
plt.axvline(min(bounds), color='red', alpha=0.3, linewidth=3.5)
plt.subplots_adjust(left=0.05, bottom=0.4, right=0.95, top=0.9)
plt.show()
I would like to use varying degrees of red color to represent the different importance of each time element and fill in that region.
The example code is shown below.
import matplotlib.pyplot as plt
X_example = np.random.rand(400)
importance_values = np.random.rand(400)
plt.figure(figsize=(13,7))
plt.plot(X_example)
for j in range(len(X_example)):
plt.axvspan(xmin=j, xmax=j+1,facecolor="r",alpha=importance_values[j])
It generates a graph like:
Now I would like to add a colormap in this figure to show that, e.g. the light red means low importance and the dark red means high importance, just like this:
How could I achieve that in my case?
One solution would be to create a LinearSegmentedColormap which takes a list of colors and turns it into a matplotlib colorbar object. Then you can set the "alpha channel":
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap, ListedColormap
from matplotlib.colorbar import ColorbarBase
X_example = np.random.rand(400)
importance_values = np.random.rand(400)
fig, (ax, cax) = plt.subplots(ncols=2, figsize=(8,5), gridspec_kw={'width_ratios': [1, 0.05]})
ax.plot(X_example, color='b')
for j in range(len(X_example)):
ax.axvspan(xmin=j, xmax=j+1,facecolor="r",alpha=importance_values[j])
N = 20 # the number of colors/alpha-values in the colorbar
cmap = LinearSegmentedColormap.from_list(None, ['r' for i in range(N)], N=N)
alpha_cmap = cmap(np.arange(N))
alpha_cmap[:,-1] = np.linspace(0, 1, N)
alpha_cmap = ListedColormap(alpha_cmap, N=N)
cbar = ColorbarBase(cax, cmap=alpha_cmap, ticks=[0., 1],)
cbar.ax.set_yticklabels(["low importance", "high importance"])
This gives the following plot, where the two colors of the colorbar have custom labels:
You could create a colormap mixing the red color with a range of alpha values:
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, to_rgba
from matplotlib.cm import ScalarMappable
import numpy as np
X_example = np.random.rand(400)
importance_values = np.random.rand(400)
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(X_example)
for j in range(len(X_example)):
ax.axvspan(xmin=j, xmax=j + 1, facecolor="r", alpha=importance_values[j])
ax.margins(x=0)
cmap = LinearSegmentedColormap.from_list(None, [to_rgba('r', 0), 'r'])
cbar = plt.colorbar(ScalarMappable(cmap=cmap), ticks=[0, 1], pad=0.02)
cbar.ax.set_yticklabels(["low", "high"], fontsize=20)
cbar.ax.set_ylabel("importance", labelpad=-30, fontsize=20)
plt.tight_layout()
plt.show()
An example of a horizontal colorbar:
cbar = plt.colorbar(ScalarMappable(cmap=cmap), ticks=[0, 1], orientation='horizontal')
cbar.ax.set_xticklabels(["low", "high"], fontsize=20)
cbar.ax.set_xlabel("importance", labelpad=-15, fontsize=20)
I want to create a violin plot, with either matplotlib or searborn, in which the plot is colored according to a colormap.
This is what I get:
This is what I would like to get (I used Photoshop here):
How can I obtain the desired plot?
I thought there would be a better was to do this, but, based on #ImportanceOfBeingErnest's comment, I guess this is actually the way to go:
from matplotlib.path import Path
from matplotlib.patches import PathPatch
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
x = [np.random.normal(loc=i, scale=1, size=(100,)) for i in range(5)]
fig, ax = plt.subplots()
violins = ax.violinplot(x)
ymin, ymax = ax.get_ylim()
xmin, xmax = ax.get_xlim()
# create a numpy image to use as a gradient
Nx,Ny=1,1000
imgArr = np.tile(np.linspace(0,1,Ny), (Nx,1)).T
cmap = 'hsv'
for violin in violins['bodies']:
path = Path(violin.get_paths()[0].vertices)
patch = PathPatch(path, facecolor='none', edgecolor='none')
ax.add_patch(patch)
img = ax.imshow(imgArr, origin="lower", extent=[xmin,xmax,ymin,ymax], aspect="auto",
cmap=cmap,
clip_path=patch)
# colorbar
ax_divider = make_axes_locatable(ax)
cax = ax_divider.append_axes("right", size="5%", pad="2%")
norm = matplotlib.colors.Normalize(vmin=ymin, vmax=ymax)
cb = matplotlib.colorbar.ColorbarBase(cax, cmap=matplotlib.cm.get_cmap(cmap),
norm=norm,
orientation='vertical')
I use matplotlib.pyplot.pcolor() to plot a heatmap with matplotlib:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap='RdBu', vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.show()
How can I change the intensity of the 'RdBu' colormap? E.g., if the color is (0, 0, 1), it should be transformed into (0, 0, 0.8). More generally,
if the color is (x, y, z), it should be transformed into (ax, ay, az), where a is some scalar between zero and one.
This is quite similar to Stanley R's (edit: now Serenity) answer, without the (in my opinion) unnecessary complexity of loops, appending to lists, et cetera:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
a = 0.5
# Get the colormap colors, multiply them with the factor "a", and create new colormap
my_cmap = plt.cm.RdBu(np.arange(plt.cm.RdBu.N))
my_cmap[:,0:3] *= a
my_cmap = ListedColormap(my_cmap)
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
plt.subplot(121)
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap='RdBu', vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.subplot(122)
c = plt.pcolor(data, edgecolors='k', linewidths=4, cmap=my_cmap, vmin=0.0, vmax=1.0)
plt.colorbar(c)
plt.show()
You have to assembly new custom color map based on a standard.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
np.random.seed(1)
data = np.sort(np.random.rand(8,12))
plt.figure()
cmap = cm.get_cmap('RdBu', len(data)) # set how many colors you want in color map
# modify colormap
alpha = .5
colors = []
for ind in xrange(cmap.N):
c = []
for x in cmap(ind)[:3]: c.append(x*alpha)
colors.append(tuple(c))
my_cmap = matplotlib.colors.ListedColormap(colors, name = 'my_name')
# plot with my new cmap
cb = plt.pcolor(data, edgecolors='k', linewidths=4, cmap=my_cmap, vmin=0.0, vmax=1.0)
plt.colorbar(cb)
plt.show()