misalignment between grid cells and color mesh used to highlight them (in Matplotlib) - matplotlib

I am using the following code to to generate this heat map:
dim = np.arange(1, 32, 1)
fig, ax = plt.subplots(figsize=(7,9))
heatmap = ax.imshow(h, aspect=1, cmap=plt.cm.get_cmap('Blues', 5), clim=[0,100])
ax.set_ylabel("Days", fontsize=15)
ax.set_xlabel("Months", fontsize=15)
ax.set_title("Percentage of records per day", fontsize=18)
ax.set_yticks(range(0,31))
ax.set_yticklabels(dim, ha='center', minor=False)
ax.set_xticks(range(0,13,1))
ax.set_xticklabels(ylabel[7:],rotation=45, ha='right')
ax.grid(which = 'minor', color = 'w')
ax.set_facecolor('gray')
ax.xaxis.set_minor_locator(MultipleLocator(.5))
ax.yaxis.set_minor_locator(MultipleLocator(.5))
cbaxes = fig.add_axes([.8, .35, .04, .3])
cbar = fig.colorbar(heatmap, ticks = [0, 20, 40, 60, 80 ,100], label = 'Percentage', cax = cbaxes)
fig.show()
I would like to highlight all of the cells with a value greater or equal to 60.
I tried adding this to my code:
highlight = (h> 60)
highlight = np.ma.masked_less(highlight, 1)
ax.pcolormesh(highlight, facecolor = 'None')
and got this:
I am almost there but the cells and the mesh are misaligned. How could I fix this?

The cells in a heatmap are centered on integers, this means for example that the cell with index 0,0 is in fact -0.5 to 0.5 on both axes. You have to subtract 0.5 to the coordinates of your highlights.

Thanks to mozway's comment I was able to fix my problem. I changed the beginning of my code to:
highlight = (h> 60)
highlight = np.ma.masked_less(highlight, 1)
x = np.arange(-0.5,12,1) # len = 10
y = np.arange(-0.5,30,1) # len = 6
X, Y = np.meshgrid(x, y)
and change the line plotting the color mesh to:
ax.pcolormesh(x,y,highlight, facecolor = 'None', edgecolors = 'w',shading='auto', zorder=2)
I also had to set the z-order of the color mesh to be greater than the grid lines (zorder=2 and zorder=1 respectively).

Related

Grid lines not aligned with cells when defining minor ticks in Matplotlib Heatmap

I am using the code below to generate this heatmap:
dim = np.arange(1, 32, 1)
fig, ax = plt.subplots(figsize=(7,9))
heatmap = ax.imshow(h.T, cmap=plt.cm.get_cmap('Blues', 4), clim=[1,144])
cbaxes = fig.add_axes([.8, .35, .04, .3])
cbar = fig.colorbar(heatmap, ticks = [1, 36, 72, 108, 144], label = 'Number of valid records per day', cax = cbaxes)
ax.set_ylabel("Days", fontsize=15)
ax.set_xlabel("Months", fontsize=15)
ax.set_title("Number of valid records per day", fontsize=20)
ax.set_yticks(range(0,31))
ax.set_yticklabels(dim, ha='center', minor=False, fontsize=12)
ax.set_xticks(range(0,13,1))
ax.set_xticklabels(ylabel, rotation = 45, ha = 'right')
ax.set_facecolor('gray')
cbar.set_label('Number of valid records')
ax.xaxis.set_minor_locator(MultipleLocator(0.5))
ax.yaxis.set_minor_locator(MultipleLocator(0.5))
ax.tick_params(axis='y', which='major', pad=10)
ax.grid(which = 'minor', color = 'w')
fig.show()
As you can see there is a slight offset of the gridlines with respect to the heat map cells. Why is that? How can I fix it?
Thanks to the comment left by Jody Klymak, I added the following line of code at the beginning of my notebook and it solved the problem:
matplotlib.rcParams['figure.dpi'] = 300

Tick labels in between colors (discrete colorer)

Hi I want to put the ticklabels between colors (center of the intervals), and the figure is plotted by discrete colors. But the min value is not 0. How can I write the code to do that?
I used following code to do that, but what I got is wrong...
n_clusters = len(cbar_tick_label)
tick_locs = (np.arange(n_clusters)+0.5)*(n_clusters-1)/(n_clusters)
cbar.set_ticks(tick_locs)
cbar.set_ticklabels(cbar_tick_label)
This code is from question: Discrete Color Bar with Tick labels in between colors. But it does not work when the min value of data is not zero.
Thanks!
Suppose there are N (e.g. 6) clusters. If you subdivide the range from the lowest number (e.g. 5) to the highest number (e.g. 10) into N equal parts, there will be a tick at every border between color cells. Subdividing into 2*N+1 equal parts, will also have a tick in the center of each color cell. Now, skipping every other of these 2*N+1 ticks will leave us with only the cell centers. So, np.linspace(5, 10, 6*2+1) are the ticks for borders and centers; taking np.linspace(5, 10, 6*2+1)[1::2] will be only the centers.
import numpy as np
import matplotlib.pyplot as plt
x, y = np.random.rand(2, 100)
c = np.random.randint(5, 11, x.shape)
n_clusters = c.max() - c.min() + 1
fig, ax = plt.subplots()
cmap = plt.get_cmap('inferno_r', n_clusters)
scat = ax.scatter(x, y, c=c, cmap=cmap)
cbar = plt.colorbar(scat)
tick_locs = np.linspace(c.min(), c.max(), 2 * n_clusters + 1)[1::2]
cbar_tick_label = np.arange(c.min(), c.max() + 1)
cbar.set_ticks(tick_locs)
cbar.set_ticklabels(cbar_tick_label)
plt.show()

Issue adjusting figsize with matplotlib barh subplot

I've tried specifying in a few ways but have not been able to get this figure any bigger than what's shown.
category_names = ['Database', 'Frontend', 'QA', 'ML', 'Fullstack']
labels = list(final_df.index)
data = np.array(final_df.iloc[:, 1:])
data_cum = data.cumsum(axis=1)
category_colors = plt.get_cmap('RdYlGn')(np.linspace(0, 1000, data.shape[1]))
fig, ax = plt.subplots(figsize=(100,75))
ax.invert_yaxis()
# ax.xaxis.set_visible(False)
ax.set_xlim(0, 200)
for i, (colname, color) in enumerate(zip(category_names, category_colors)):
widths = data[:, i]
starts = data_cum[:, i] - widths
ax.barh(labels, widths, left=starts, height=0.5,
label=colname, color=color)
xcenters = starts + widths / 2
r, g, b, _ = color
text_color = 'white' if r * g * b < 0.5 else 'darkgrey'
for y, (x, c) in enumerate(zip(xcenters, widths)):
ax.text(x, y, str(int(c)), ha='center', va='center',
color=text_color, fontsize=15)
If I make the figsize any bigger, the kernel dies and I've tried adjusting height and np.linspace params, as well as trying to set size with fig.set_size_inches. Any ideas on what's going on here?

Shapefile zooming to plot with geopandas

I have a shapefile of Italy and I'm plotting the GIS Data on it. Thing is I've got a small trajectory of a bus going within a city(Rome) and when i`m plotting, it appears like 1 dot. I guess because of my map.
How to zoom the map (.shp) ?
street_map = gpd.read_file("roads.shp")
...
...
fig,ax = plt.subplots(figsize = (20,15))
street_map.plot(ax = ax, alpha = 0.4, color = "grey")
geo_df[geo_df['Perc_'] > 25].plot(ax = ax, markersize = 20, color = "blue",
marker = "o", label = "Neg")
geo_df[geo_df['Perc_'] < 25].plot(ax = ax, markersize = 20, color = "red",
marker = "^", label = "Pos")
plt.legend(prop={'size':15})
Based on your 1st image, it is possible to get the zoom-in plot by specifying proper x and y limits.
...
ax.set_ylim([40.4, 47.2])
ax.set_xlim([7.0, 14.4])
(Place this code before plt.legend().
Hope this is useful.

Change markerfacecolor for some of the markers in Matplotlib

I have a plot that shows markers in a circle. I want to be able to change the colour of 3 of them. I've tried using a variable for markerfacecolor as follows but that doesn't work:
angle = 0.0
colorR = 'red'
angleUpdate = 2 * numpy.pi / (len(v.T))
for i in range(len(v.T)):
x = numpy.sin(angle)
y = numpy.cos(angle)
angle += angleUpdate
if i < 3:
colorR = 'green'
v[0, i] = x
v[1, i] = y
plt.plot(v[0], v[1], 'ko', markerfacecolor = colorR, markersize = 70, clip_on = False)
plt.show()
Is there a way of doing this?
In your plot 'ko' means put a black circle marker; k stands for black. You should try:
plt.plot(v[0], v[1], 'o', markerfacecolor = 'red')
To get the abbreviation of other symbols and colors try:
help(plt.plot)
You can either achieve your case using plot or scatter, depending on what you are doing:
import pylab as plt
x=[1,2,3,4,5,6,7,8,9,10]
plt.plot(x[:5],x[:5],'o',c='r',markersize=10)
plt.plot(x[5:],x[5:],'o',c='b',markersize=10)
plt.show()
will generate,
Similarly, you can also use
plt.scatter(x[:5],x[:5],c='r',s=100)
plt.scatter(x[5:],x[5:],c='b',s=100)