Colorbar scaling in ImageGrid - matplotlib

Why is the following behaviour happening to my colorbars.. and how do I get it to behave "normal"?
x_array = np.random.rand(5, 15, 10)
x_array = np.array([np.random.randint(1,20) * x for x in x_array])
minmax_array = [-2, 2]
f = plt.figure()
ag = axes_grid.ImageGrid(f, rect=(1, 1, 0), nrows_ncols=(1,5), cbar_mode='each',
cbar_pad=0.05, axes_pad=0.5)
for j in range(5):
x_temp = x_array[j, :, :]
im = ag[j].imshow(x_temp)
ag.cbar_axes[j].colorbar(im)
ag.cbar_axes[j].set_yticks(minmax_array)
The result of this is shown below
As you can see, since I supply colorbar range outside of the values of the arrays.. I get this weird scaling of the colorbar.
But why cant it scale

The reason for this is because vmin and vmax have not been set in imshow. If we execute the following code
x_array = np.random.rand(5, 15, 10)
x_array = np.array([np.random.randint(1,20) * x for x in x_array])
minmax_array = [-2, 2]
f = plt.figure()
ag = axes_grid.ImageGrid(f, rect=(1, 1, 0), nrows_ncols=(1,5), cbar_mode='each',
cbar_pad=0.05, axes_pad=0.5)
for j in range(5):
x_temp = x_array[j, :, :]
im = ag[j].imshow(x_temp, vmin=minmax_array)
ag.cbar_axes[j].colorbar(im)
ag.cbar_axes[j].set_yticks(minmax_array)
Note that "if vmin is a length2 sequence, interpret it as (vmin, vmax) which is used to support setp"

Related

How to remove noise-only rows from a numpy array?

I want to remove rows from a Numpy array, where there is just noise and a random constant offset.
My data looks similar to this:
offset = np.array([0.2, 3.2])
signal = np.sin(np.arange(0, 2 * np.pi, 0.1))
null = np.zeros_like(signal)
data_block = np.array([signal, null]).T
padding = np.zeros((10, 2))
block = np.vstack((padding, data_block, padding)) + offset
# add noise
shape = block.shape
noise = np.random.rand(shape[0], shape[1]) * .01
everything = noise + block
In reality, there is no step but rather a smooth transition from the offset to the data. It is like first there is the offset, which starts to move, once the data block starts, and becomes another offset when it stops. The noise amplitude is much smaller than the data amplitude.
I would like to retrieve the rows with the data block from everything, preferably based on continuous, smooth change in the data block. How can I do that?
This is my best effort on identifying the data_block. I would be happy if it could be improved!
import numpy as np
offset = np.array([0.2, 3.2])
signal = np.sin(np.arange(0, 2 * np.pi, 0.1))
null = np.zeros_like(signal)
data_block = np.array([signal, null]).T
padding = np.zeros((10, 2))
block = np.vstack((padding, data_block, padding)) + offset
# add noise
shape = block.shape
noise = np.random.rand(shape[0], shape[1]) * .01
everything = noise + block
from matplotlib import pyplot as plt
x = np.arange(shape[0])
plt.plot(x, everything[:, 0])
plt.plot(x, everything[:, 1])
plt.show()
diff_everything = np.diff(everything, axis=0)
x = np.arange(shape[0] - 1)
plt.plot(x, diff_everything[:, 0])
plt.plot(x, diff_everything[:, 1])
plt.show()
mask = (np.linalg.norm(diff_everything[:, :], axis=1) > 0.01)
mask = np.append(mask, False)
data = everything[mask, :]
shape = data.shape
x=np.arange(0,shape[0])
plt.plot(x, data[:, 0])
plt.plot(x, data[:, 1])
plt.show()

Is there a way to propelly align the two yAxis

The problem is the y_h = 1 is not aligned properly with the y = 0.3 and so on, how do i fix this? Below i left a picture of the problem im facing and the code.
yaxis's not aligned
x = 2
y = np.array([0.3, 0.11, 0.43])
y_h = np.array([1, 2, 3])
fig, host = plt.subplots(figsize=(8, 5))
fig.subplots_adjust(right=0.75)
colormap = plt.get_cmap("gist_rainbow")
colors = [colormap(i) for i in np.linspace(0, 1, y.size)]
line = host.twinx()
#plot the lines the give them colors and labels
for i in range(y.size):
p = line.plot([x - x, x], [y_h[i], y[i]], color=colors[i], label="p"+str(i))
#append the line labels to a list
'''for i in range(y.size):
pis.append('p'+str(i))'''
host.set_xlim(0, x)
host.set_ylim(0, y_h.size)
line.set_ylim(0, max(y))
host.set_xlabel("Rev_Count")
host.set_ylabel("Value")
line.set_ylabel('Value_Header')
plt.show()

How to Add More Spacing Between X Axis Ticks and Labels MATPLOTLIB

I've been looking online for help but nothing that I have seen is helping me to add space between the xticks without losing any xtick labels on the x axis. Here is my code and the things that I have tried to get the figure below to the current layout. Is there an auto-adjust that works? "plt.tight_layout" should do that but doesn't seem to work for me. thank you for help here. And, the plt.suptitle is not centered above the month (February).
#CALC VARIABILITY AND PLOT BOXPLOTS for ea month
sitenames = df3.plant_name.unique().tolist()
months = ['JANUARY','FEBRUARY','MARCH','APRIL','MAY','JUNE','JULY','AUGUST','SEPTEMBER','OCTOBER','NOVEMBER','DECEMBER']
from datetime import datetime
monthn = datetime.now().month
newList = list()
for i in range(monthn-1):
newList.append(months[(i)%12])
print(newList)
for i, month in enumerate(newList,1):
#plt.figure()
#fig, ax = plt.subplots()
#ax = df3[df3['month']==i].boxplot(by='plant_name',column='Var',grid=False)
datey = datetime.today().strftime("%Y")
ax = df3[df3['month']==i].plot(kind='scatter',x='plant_name',y='Var',marker='.',s=5,grid=False)
stdp[stdp['month']==i].plot(kind='scatter', x = 'plant_name',
y='Var',color='k',marker='_',s=200,label = '1+Std', grid=False,ax=ax)
stdn[stdn['month']==i].plot(kind='scatter', x = 'plant_name',
y='Var',color='k',marker='_',s=200,label = '1-Std', grid=False,ax=ax)
stdp2[stdp2['month']==i].plot(kind='scatter', x = 'plant_name',
y='Var',color='k',marker='_',s=50,label = '2+Std',grid=False,ax=ax)
stdn2[stdn2['month']==i].plot(kind='scatter', x = 'plant_name',
y='Var',color='k',marker='_',s=50,label = '2-Std',grid=False,ax=ax)
medn[medn['month']==i].plot(kind='scatter', x = 'plant_name',
y='Var',color='g',marker='_',s=90,label = 'p50',grid=False,ax=ax)
df3c[df3c['month']==i].plot(kind='scatter', x = 'plant_name', y='Var',color='r',label =
datey,grid=False,ax=ax)
# Save the default tick positions, so we can reset them...
locs, labels = plt.xticks()
plt.xticks(rotation=90, ha='center')
plt.suptitle('1991-2020 ERA5 WIND PRODUCTION',y=1)
plt.title(months[i-1])
plt.xlabel('SITE')
plt.ylabel('VARIABILITY')
#plt.legend()
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5),prop={'size': 8})
plt.tick_params(axis='x', which='major', labelsize=10)
plt.tight_layout(rect=[0, 0, 2, 1])
plt.subplots_adjust(bottom=0.1)
Without "plot_tight_layout(rect[0, 0, 2, 1])"
And, with "plot_tight_layout(rect[0, 0, 2, 1])" included:

contour lines from the edge of a map don't show up on basemap

I'm drawing several contour lines over a basemap projection as shown in the following figure:.
There are 3 contours that are not drawn completely (in Oregon, Washington and California) and seems like there is this line that has cut all 3 of them in the same latitude. I'm not sure how to solve this problem.
I added the number of interpolation points, didn't help. changed the ll and ur points to include more area didn't help.
The code is below (not reproducible but might help):
def visualise_bigaus(mus, sigmas, corxys , output_type='pdf', **kwargs):
lllat = 24.396308
lllon = -124.848974
urlat = 49.384358
urlon = -66.885444
fig = plt.figure(figsize=(4, 2.5))
ax = fig.add_subplot(111, axisbg='w', frame_on=False)
m = Basemap(llcrnrlat=lllat,
urcrnrlat=urlat,
llcrnrlon=lllon,
urcrnrlon=urlon,
resolution='i', projection='cyl')
m.drawmapboundary(fill_color = 'white')
#m.drawcoastlines(linewidth=0.2)
m.drawcountries(linewidth=0.2)
m.drawstates(linewidth=0.2, color='lightgray')
#m.fillcontinents(color='white', lake_color='#0000ff', zorder=2)
#m.drawrivers(color='#0000ff')
m.drawlsmask(land_color='gray',ocean_color="#b0c4de", lakes=True)
lllon, lllat = m(lllon, lllat)
urlon, urlat = m(urlon, urlat)
mlon, mlat = m(*(mus[:,1], mus[:,0]))
numcols, numrows = 1000, 1000
X = np.linspace(mlon.min(), urlon, numcols)
Y = np.linspace(lllat, urlat, numrows)
X, Y = np.meshgrid(X, Y)
m.scatter(mlon, mlat, s=0.2, c='red')
shp_info = m.readshapefile('./data/us_states_st99/st99_d00','states',drawbounds=True, zorder=0)
printed_names = []
ax = plt.gca()
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
for spine in ax.spines.itervalues():
spine.set_visible(False)
for k in xrange(mus.shape[0]):
#here x is longitude and y is latitude
#apply softplus to sigmas (to make them positive)
sigmax=np.log(1 + np.exp(sigmas[k][1]))
sigmay=np.log(1 + np.exp(sigmas[k][0]))
mux=mlon[k]
muy=mlat[k]
corxy = corxys[k]
#apply the soft sign
corxy = corxy / (1 + np.abs(corxy))
#now given corxy find sigmaxy
sigmaxy = corxy * sigmax * sigmay
#corxy = 1.0 / (1 + np.abs(sigmaxy))
Z = mlab.bivariate_normal(X, Y, sigmax=sigmax, sigmay=sigmay, mux=mux, muy=muy, sigmaxy=sigmaxy)
#Z = maskoceans(X, Y, Z)
con = m.contour(X, Y, Z, levels=[0.02], linewidths=0.5, colors='darkorange', antialiased=True)
'''
num_levels = len(con.collections)
if num_levels > 1:
for i in range(0, num_levels):
if i != (num_levels-1):
con.collections[i].set_visible(False)
'''
contour_labels = False
if contour_labels:
plt.clabel(con, [con.levels[-1]], inline=True, fontsize=10)
'''
world_shp_info = m.readshapefile('./data/CNTR_2014_10M_SH/Data/CNTR_RG_10M_2014','world',drawbounds=False, zorder=100)
for shapedict,state in zip(m.world_info, m.world):
if shapedict['CNTR_ID'] not in ['CA', 'MX']: continue
poly = MplPolygon(state,facecolor='gray',edgecolor='gray')
ax.add_patch(poly)
'''
if iter:
iter = str(iter).zfill(3)
else:
iter = ''
plt.tight_layout()
plt.savefig('./maps/video/gaus_' + iter + '.' + output_type, frameon=False, dpi=200)
The problem is the meshgrid not covering the complete map. The meshgrid simply doesn't have any points at the positions where you want to draw the gaussian contour line.
An example to reproduce this behaviour is the following, where the meshgrid in x directio starts at -1, such that points lower than that are not drawn.
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import numpy as np
fig, ax=plt.subplots()
ax.plot([-2,2],[-2,-2], alpha=0)
X,Y = np.meshgrid(np.linspace(-1,2),np.linspace(-2,2))
Z = mlab.bivariate_normal(X, Y, sigmax=1., sigmay=1., mux=0.1, muy=0.1, sigmaxy=0)
con = ax.contour(X, Y, Z, levels=[Z.max()/3, Z.max()/2., Z.max()*0.8],colors='darkorange')
plt.show()
A similar problem occurs in the code from the question.
While in Y direction, you use the complete map, Y = np.linspace(lllat, urlat, numrows), in X direction you restrict the mesh to start at mlon.min(),
X = np.linspace(mlon.min(), urlon, numcols)
The solution would of course be not to start the mesh in Portland, but somewhere in the ocean, i.e. at the edge of the shown map.

Colormap is not categorizing the data properly

Here is my script to plot data from a Geogtiff file using basemap. The data is categorical and there are 13 categories within this domain. The problem is that some categories get bunched up into one colour and thus some resolution is lost.
Unfortunately, I do not know how to fix this. I read that plt.cm.get_cmp is better for discrete datasets but I have not gotten it to work unfortunately.
gtif = 'some_dir'
ds = gdal.Open(gtif)
data = ds.ReadAsArray()
gt = ds.GetGeoTransform()
proj = ds.GetProjection()
xres = gt[1]
yres = gt[5]
xmin = gt[0] + xres
xmax = gt[0] + (xres * ds.RasterXSize) - xres
ymin = gt[3] + (yres * ds.RasterYSize) + yres
ymax = gt[3] - yres
xy_source = np.mgrid[xmin:xmax+xres:xres, ymax+yres:ymin:yres]
ds = None
fig2 = plt.figure(figsize=[12, 11])
ax2 = fig2.add_subplot(111)
ax2.set_title("Land use plot")
bm2 = Basemap(ax=ax2,projection='cyl',llcrnrlat=ymin,urcrnrlat=ymax,llcrnrlon=xmin,urcrnrlon=xmax,resolution='l')
bm2.drawcoastlines(linewidth=0.2)
bm2.drawcountries(linewidth=0.2)
data_new=np.copy(data)
data_new[data_new==255] = 0
nbins = np.unique(data_new).size
cb =plt.cm.get_cmap('jet', nbins+1)
img2 =bm2.imshow(np.flipud(data_new), cmap=cb)
ax2.set_xlim(3, 6)
ax2.set_ylim(50,53)
plt.show()
labels = [str(i) for i in np.unique(data_new)]
cb2=bm2.colorbar(img2, "right", size="5%", pad='3%', label='NOAH Land Use Category')
cb2.set_ticklabels(labels)
cb2.set_ticks(np.unique(data_new))
Here are the categories that are found within the domain (numbered classes):
np.unique(data_new)
array([ 0, 1, 4, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17], dtype=uint8)
Thanks so much for any help here. I have also attached the output image that shows the mismatch. (not working)
First, this colormap problem is independent of the use of basemap. The following is therefore applicable to any matplotlib plot.
The problem here is that creating a colormap from n values distributes those values equally over the colormap range. Some values from the image therefore fall into the same colorrange within the colormap.
To prevent this, one can generate a colormap with the initial number of categories as shown below.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors
# generate some data
data = np.array( [ 0, 1, 4, 5, 7, 10]*8 )
np.random.shuffle(data)
data = data.reshape((8,6))
# generate colormap and norm
unique = np.unique(data)
vals = np.arange(int(unique.max()+1))/float(unique.max())
cols = plt.cm.jet(vals)
cmap = matplotlib.colors.ListedColormap(cols, int(unique.max())+1)
norm=matplotlib.colors.Normalize(vmin=-0.5, vmax=unique.max()+0.5)
fig, ax = plt.subplots(figsize=(5,5))
im = ax.imshow(data, cmap=cmap, norm=norm)
for i in range(data.shape[0]):
for j in range(data.shape[1]):
ax.text(j,i,data[i,j], color="w", ha="center", va="center")
cb = fig.colorbar(im, ax=ax, norm=norm)
cb.set_ticks(unique)
plt.show()
This can be extended to exclude the colors not present in the image as follows:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors
# generate some data
data = np.array( [ 0, 1, 4, 5, 7, 10]*8 )
np.random.shuffle(data)
data = data.reshape((8,6))
unique, newdata = np.unique(data, return_inverse=1)
newdata = newdata.reshape(data.shape)
# generate colormap and norm
new_unique = np.unique(newdata)
vals = np.arange(int(new_unique.max()+1))/float(new_unique.max())
cols = plt.cm.jet(vals)
cmap = matplotlib.colors.ListedColormap(cols, int(new_unique.max())+1)
norm=matplotlib.colors.Normalize(vmin=-0.5, vmax=new_unique.max()+0.5)
fig, ax = plt.subplots(figsize=(5,5))
im = ax.imshow(newdata, cmap=cmap, norm=norm)
for i in range(newdata.shape[0]):
for j in range(newdata.shape[1]):
ax.text(j,i,data[i,j], color="w", ha="center", va="center")
cb = fig.colorbar(im, ax=ax, norm=norm)
cb.ax.set_yticklabels(unique)
plt.show()