Matplotlib Colormap Set to Black Below Threshold - python

I am using imshow to plot a sparse matrix and would like for 0 entries to be colored black. I followed the advice given in this answer, but my plot still has white for 0 entries, which is confusing since the highest weighted entries are hot yellow. Any help is much appreciated.
Here is my code:
cmap1 = cm.get_cmap('inferno', 128)
cmap1.set_under(color='black')
im_plot = ax1.imshow(P_im,cmap=cmap1,norm=LogNorm(vmin=1e-30, vmax=np.max(P_im)+1e-15))
ax1.set_title("Title",size=10)

Check this code:
from matplotlib import cm
import numpy as np
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots(1, 1, figsize = (4, 4))
x = np.random.binomial(n = 1, p = 0.1, size = (20, 20))
cmap1 = cm.get_cmap('Greys_r', 2)
im_plot = ax1.imshow(x, cmap = cmap1)
ax1.set_title("Title", size = 10)
plt.show()
which gives me this image:
I used x = np.random.binomial(n = 1, p = 0.1, size = (20, 20)) to generate a random sparse matrix, replace it with your data.

Related

Custom colormap boundaries for segmented colormap

I have the following picture with data available for several vectors with some quantified feature:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as colors
fig = plt.figure(figsize=(10,7))
ax = fig.add_subplot()
category = [0,0,0,0.1,0.4,0.9,1.5]
r = np.random.uniform(size=[len(category)*100]).reshape(len(category),100)
norm = matplotlib.colors.Normalize(vmin=min(category), vmax=max(category))
bounds = np.array([0, 0.3, 0.5, 1.5])
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=3)
cmap = matplotlib.cm.ScalarMappable(norm=norm, cmap=colors.ListedColormap(['green', 'blue', 'red']))
cmap.set_array([])
for no, cat in enumerate(category):
ax.plot(r[no][r[no]>0.1],no*np.ones(100)[r[no]>0.1],'o',color=cmap.to_rgba(category[no]))
cbar = fig.colorbar(cmap, ax=ax, pad=0.01)
I am wondering is there any way to move colormap feature boundaries to correspond to the boundaries between vectors in the picture? (as denoted by black arrows)
I thought that spacing='proportional' will help me, however, it depends on the feature, and I want to make it dependent on the number of vectors having some range of features.
Additionally, is it possible to use these custom boundaries for gradient (not segmented) colormap?
I found the way to do what I asked for.
The idea is to create a new variable that will be dependent on the number of vectors in each group and use this variable with spacing='proportional'. Here is the MWE:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as colors
fig = plt.figure(figsize=(10,7))
ax = fig.add_subplot()
category = np.array([0,0,0,0.1,0.4,0.9,1.5])
r = np.random.uniform(size=[len(category)*100]).reshape(len(category),100)
norm = matplotlib.colors.Normalize(vmin=min(category), vmax=max(category))
lev1 = 0.3
lev2 = 0.5
gr0 = (category<=lev1).sum()
gr2 = (category>lev2).sum()
gr1 = len(category) - gr0 - gr2
frac = np.array([gr0,gr1,gr2])/len(category)
bounds = np.array([0, frac[0], frac[1]+frac[0], 1])
gr_color = np.where(category<lev1,0,np.where(category>=lev2,1,frac[0]+frac[1]/2))
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=3)
cmap = matplotlib.cm.ScalarMappable(norm=norm, cmap=colors.ListedColormap(['green', 'blue', 'red']))
cmap.set_array([])
for no, cat in enumerate(category):
ax.plot(r[no][r[no]>0.1],no*np.ones(100)[r[no]>0.1],'o',color=cmap.to_rgba(gr_color[no]))
cbar = fig.colorbar(cmap, ax=ax, pad=0.01,spacing='proportional')
dic = {bounds[0] : 0 ,bounds[1] : lev1, bounds[2] : lev2,bounds[3] : "1.5"}
labels = [bounds[i] if t not in dic.keys() else dic[t] for i,t in enumerate(bounds)]
cbar.ax.set_yticklabels(labels)

How to change the color of individual histograms in DataFrame.hist() or DataFrame.plot.hist( subplots = True ) function?

How to change the color of individual histograms in DataFrame.hist() function ?
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
# plot style
mpl.style.use("ggplot")
# DataFrame
df = pd.DataFrame({"A": np.random.randint(1, 5, size = 20),
"B": np.random.randint(4, 12, size = 20),
"C": np.random.randint(3, 10, size = 20),
"D": np.random.randint(100, 105, size = 20)})
df.hist(figsize = (8,6)
Desired Output
fig, axes = plt.subplots(nrows = 2, ncols =2, figsize = (8, 6))
colors = ["#e24a33", "#348abd", "#988ed5", "#777777"] # whatever the colors may be but it should be different for each histogram.
for index, column in enumerate(df.columns):
ax = axes.flatten()[index]
ax.hist(df[column], color = colors[index], label = column)
ax.legend(loc = "best")
plt.suptitle("Desired Histograms", size = 20)
plt.show()
DataFrame.plot.hist() is affecting the number of bins in each histogram.
# one line code for above , but only issues with X axis and Y axis limits, which is effecting number of bins in each histogram.
df.plot.hist(subplots = True, layout = (2,2), figsize = (8,6))
plt.suptitle("#Bins effected in each histogram", size = 20)
**Is it possible to get the desired histograms by using the inbuilt function ** df.hist() or df.plot.hist(suplots = True)?

How can I get the pixel colors in matplotlib?

I am plotting a collection of rectangles with matplotlib.patches. My code is:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig = plt.figure(figsize=(14, 10))
for i in rectangles_list:
ax1 = fig.add_subplot(111, aspect='equal')
ax1.add_patch(patches.Rectangle(
(x[i], y[i]),
width[i],
height[i],
alpha = 1.0,
facecolor = colors_list[i]
)
)
plt.show()
The rectangles may be overlapping, therefore some of them may be completely hidden. Do you know if it is possible to get the colors of the visible rectangles? I mean the colors of the rectangles that are not completely hidden and therefore that can be actually viewed by the user. I was thinking to some function that returns the color of the pixels, but more intelligent ideas are welcome. If possible, I'd prefer to not use PIL. Unfortunately I cannot find any solution on the internet.
Following Vlass Sokolov comment and this Stackoverflow post by Joe Kington, here is how you could get a numpy array containing all the unique colors that are visible on a matplotlib figure:
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import numpy as np
plt.close('all')
# Generate some data :
N = 1000
x, y = np.random.rand(N), np.random.rand(N)
w, h = np.random.rand(N)/10 + 0.05, np.random.rand(N)/10 + 0.05
colors = np.vstack([np.random.random_integers(0, 255, N),
np.random.random_integers(0, 255, N),
np.random.random_integers(0, 255, N)]).T
# Plot and draw the data :
fig = plt.figure(figsize=(7, 7), facecolor='white')
ax = fig.add_subplot(111, aspect='equal')
for i in range(N):
ax.add_patch(Rectangle((x[i], y[i]), w[i], h[i], fc=colors[i]/255., ec='none'))
ax.axis([0, 1, 0, 1])
ax.axis('off')
fig.canvas.draw()
# Save data in a rgb string and convert to numpy array :
rgb_data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
rgb_data = rgb_data.reshape((int(len(rgb_data)/3), 3))
# Keep only unique colors :
rgb_data = np.vstack({tuple(row) for row in rgb_data})
# Show and save figure :
fig.savefig('rectangle_colors.png')
plt.show()

Is it possible to change the width of an imshow matplotlib visualization? [duplicate]

This question already has answers here:
Imshow: extent and aspect
(2 answers)
Closed 6 years ago.
I would like to make a figure using imshow in matplotlib for which I can usefully set the width and height. I thought I could use figsize to do that, but it's performing the way I thought it would.
For example, using the following MWE:
import matplotlib.pyplot as plt
import numpy as np
N = 100
width = 20
height = 20
Z = np.random.random((width,height))
G = np.zeros((width,height,3))
# Here we set the RGB for each pixel
G[Z>0.5] = [1,1,1]
G[Z<0.5] = [0,0,0]
plt.figure(figsize = (2, 5))
plt.imshow(G,interpolation='nearest')
plt.grid(False)
plt.show()
Here is what I get:
If I change figsize = (2, 5) to figsize = (2, 2), for example, the proportions don't change!
After trying a few different values I think this is because the graph is being rendered as a box instead of as a rectangle: no matter what I set figsize to the individual matrix entries are a constant box.
Is there a command that I can use to e.g. tell matplotlib to expand out to e.g. 800x400px?
The default behavior of imshow is to set the aspect ratio of the host axes to be 'equal' (that is squares in data-units are squares in screen space). If you do not care about this, just set the aspect to 'auto'.
import matplotlib.pyplot as plt
import numpy as np
N = 100
width = 20
height = 20
Z = np.random.random((width, height))
G = np.zeros((width, height, 3))
# Here we set the RGB for each pixel
G[Z > 0.5] = [1, 1, 1]
G[Z < 0.5] = [0, 0, 0]
fig, ax = plt.subplots(figsize=(2, 5))
ax.imshow(G, interpolation='nearest')
ax.set_aspect('auto')
plt.show()

matplotlib hist() autocropping range

I am trying to make a histgram over a specific range but the matplotlib.pyplot.hist() function keeps cropping the range to the bins with entries in them. A toy example:
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(-100,100,1000)
nbins = 100
xmin = -500
xmax = 500
fig = plt.figure();
ax = fig.add_subplot(1, 1, 1)
ax.hist(x, bins=nbins,range=[xmin,xmax])
plt.show()
Gives a plot with a range [-100,100]. Why is the range not [-500,500] as specified?
(I am using the Enthought Canopy 1.4 and sorry but I do not have a high enough rep to post an image of the plot.)
Actually, it works if you specify with range an interval shorter than [-100, 100]. For example, this work :
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(-100, 100, 1000)
plt.hist(x, bins=30, range=(-50, 50))
plt.show()
If you want to plot the histogram on a range larger than [x.min(), x.max()] you can change xlim propertie of the plot.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(-100, 100, 1000)
plt.hist(x, bins=30)
plt.xlim(-500, 500)
plt.show()
the following code is for making the same y axis limit on two subplots
f ,ax = plt.subplots(1,2,figsize = (30, 13),gridspec_kw={'width_ratios': [5, 1]})
df.plot(ax = ax[0], linewidth = 2.5)
ylim = [df['min_return'].min()*1.1,df['max_return'].max()*1.1]
ax[0].set_ylim(ylim)
ax[1].hist(data,normed =1, bins = num_bin, color = 'yellow' ,alpha = 1)
ax[1].set_ylim(ylim)

Categories