Matplotlib hist2d() and numpy masked_where()? - matplotlib

I may be misunderstanding how numpy.ma.masked_where() works, but it doesn't seem to work properly with matplotlib hist2d().
In the code below, I create an ndarray, mask it, then plot the original and masked ndarrays with matplotlib.pyplot.plot(). This works.
However, when I try to plot both with matplotlib.pyplot.hist2d(), the mask doesn't seem to be taken into account. I have tested this with matplot lib 1.3.1 and 3.2.1, and with numpy 1.18.5.
Any suggestions?
import math
import numpy as np
import time
import sys
import numpy.ma as ma
import matplotlib
import matplotlib.pyplot as plt
from scipy.stats import expon, poisson, uniform, norm
print(matplotlib.__version__, np.__version__)
nSiz=10000
maxx, maxy = 1.0, 10.0
x, y, z = uniform.rvs(scale=maxx, size=nSiz), uniform.rvs(scale=maxy, size=nSiz), norm.rvs(scale=1.0, size=nSiz)
binx, biny = np.linspace(0, maxx, 20), np.linspace(0, maxy, 20)
d = np.array([(xx, yy, zz) for xx, yy, zz in zip(x, y, z)], dtype=[('X', 'f4'), ('Y', 'f4'), ('Z', 'f4')])
print("Col titles: " + str(d.dtype.names))
dc = ma.masked_where(d['X'] < 0.5, d) # Mask data
fig, axx = plt.subplots(2, 2, figsize=(10, 10), dpi=300)
ax = axx.ravel()
ax[0].plot(d['X'], d['Y'], 'bv', ms=3)
ax[1].plot(dc['X'], dc['Y'], 'ro', ms=6, alpha=0.1) ### Mask seems to work
ax[2].hist2d(d['X'], d['Y'], bins=[binx, biny], cmap='Blues')
ax[3].hist2d(dc['X'], dc['Y'], bins=[binx, biny], cmap='Blues') ### Mask doesn't seem to work
for axx in ax:
axx.set_xlabel(d.dtype.names[0], fontsize = 15)
axx.set_ylabel(d.dtype.names[1], fontsize = 15)
axx.set_xlim(0.0, maxx)
axx.set_ylim(0.0, maxy)
ax[0].set_title('No cut')
ax[1].set_title('Cut')
plt.show()
The last plot is incorrect:

Turns out a simple solution in my case is not to use:
dc = ma.masked_where(d['X'] < 0.5, d)
but instead to simply replace that command with:
dc = d[d['X'] < 0.5]
That does the job for me (though I still don't know the purpose of numpy.ma.masked_where()).

Related

pyplot: loglog contour with labels fix angle

This is an extension of a related question.
I intend to make a contour plot, with labeled contours, then change the axes scales to 'log'.
This works fine except that the rotation of the contour labels is not adjusted. Can this be fixed?
loglog = False
import matplotlib.pyplot as plt
import numpy as np
x = (np.linspace(0, 10))
y = (np.linspace(0, 10))
X, Y = np.meshgrid(x, y)
C = plt.contour(X, Y, np.sqrt(X) * Y)
plt.clabel(C, inline=1, fontsize=10)
plt.xlim(1, 10)
plt.ylim(1, 10)
if loglog: plt.xscale('log')
if loglog: plt.yscale('log')
plt.show()
The fist plot is obtained with loglog=False in the second loglog=True:
So the answer is actually obvious. Changing the the axes scale types in advance helps, of course.
Edit:
I think it makes sense to use logspace instead of linspace here.
import matplotlib.pyplot as plt
import numpy as np
x = np.logspace(0, 1, 100, base=10)
y = np.logspace(0, 1, 100, base=10)
X, Y = np.meshgrid(x, y)
plt.xlim(1, 10)
plt.ylim(1, 10)
plt.xscale('log')
plt.yscale('log')
C = plt.contour(X, Y, np.sqrt(X) * Y)
plt.clabel(C, inline=1, fontsize=10)

Matplotlib Interpolate empty pixels

I have a file 'mydata.tmp' which contains 3 colums like this:
3.81107 0.624698 0.000331622
3.86505 0.624698 0.000131237
3.91903 0.624698 5.15136e-05
3.97301 0.624698 1.93627e-05
1.32802 0.874721 1.59245
1.382 0.874721 1.542
1.43598 0.874721 1.572
1.48996 0.874721 4.27933
etc.
Then I want to make a heatmap color plot where the first two columns are coordinates, and the third column are the values of that coordinates.
Also, I would like to set the third column in log scale.
I have done this
import pandas as pd
import matplotlib.pyplot as plt
import scipy.interpolate
import numpy as np
import matplotlib.colors as colors
# import data
df = pd.read_csv('mydata.tmp', delim_whitespace=True,
comment='#',header=None,
names=['1','2','3'])
x = df['1']
y = df['2']
z = df['3']
spacing = 500
xi, yi = np.linspace(x.min(), x.max(), spacing), np.linspace(y.min(),
y.max(), spacing)
XI, YI = np.meshgrid(xi, yi)
rbf = scipy.interpolate.Rbf(x, y, z, function='linear')
ZI = rbf(XI, YI)
fig, ax = plt.subplots()
sc = ax.imshow(ZI, vmin=z.min(), vmax=z.max(), origin='lower',
extent=[x.min(), x.max(), y.min(),
y.max()], cmap="GnBu", norm=colors.LogNorm(vmin=ZI.min(),
vmax=ZI.max()))
fig.colorbar(sc, ax=ax, fraction=0.05, pad=0.01)
plt.show()
And I get this Image
which has all these empty pixels.
I am looking for something like this instead (I have done this other picture with GNUplot):
How can I do it?
You could use cmap.set_bad to define a color for the NaN values:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
import matplotlib.colors as colors
from matplotlib import cm
import copy
# Some data
x = np.array([0, 1, 3, 0, 2, 4])
y = np.array([0, 0, 0, 1, 1, 1])
z = np.array([2, 2, 3, 2, 3, 4])
# Interpolation on a grid:
nrb_points = 101
xi = np.linspace(-.5, 4.5, nrb_points)
yi = np.linspace(-.5, 1.5, nrb_points)
XI, YI = np.meshgrid(xi, yi)
xy = np.vstack((x, y)).T
XY = (XI.ravel(), YI.ravel())
ZI = griddata(points, z, XY,
method='linear',
fill_value=np.nan) # Value used [for] points
# outside of the convex hull
# of the input points.
ZI = ZI.reshape(XI.shape)
# Color map:
cmap = copy.copy(cm.jet)
cmap.set_bad('grey', 1.)
# Graph:
plt.pcolormesh(xi, yi, ZI,
#norm=colors.LogNorm(),
cmap=cmap);
plt.colorbar(label='z');
plt.plot(x, y, 'ko');
plt.xlabel('x'); plt.ylabel('y');
the result is:
I would also use griddata instead of RBF method for the interpolation. Then, point outside the input data area (i.e. the convex hull) can be set to NaN.

Python Subplot 3d Surface and Heat Map

I plan to create a figure in matplotlib, with a 3D surface on the left and its corresponding contour map on the right.
I used subplots but it only show the contour map (with blank space for the surface), and a separate figure for the surface.
Is it possible to create these plots in one figure side-by side?
EDIT: The code is as follows:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import numpy as np
x = np.arange(-5, 5, 0.25)
y = np.arange(-5, 5, 0.25)
x, y = np.meshgrid(x, y)
r = np.sqrt(x**2 + y**2)
z = np.sin(r)
fig, (surf, cmap) = plt.subplots(1, 2)
fig = plt.figure()
surf = fig.gca(projection='3d')
surf.plot_surface(x,y,z)
cmap.contourf(x,y,z,25)
plt.show()
I guess it's hard to use plt.subplots() in order to create a grid of plots with different projections.
So the most straight forward solution is to create each subplot individually with plt.subplot.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import numpy as np
x = np.arange(-5, 5, 0.25)
y = np.arange(-5, 5, 0.25)
x, y = np.meshgrid(x, y)
r = np.sqrt(x**2 + y**2)
z = np.sin(r)
ax = plt.subplot(121, projection='3d')
ax.plot_surface(x,y,z)
ax2 = plt.subplot(122)
ax2.contourf(x,y,z,25)
plt.show()
Of course one may also use the gridspec capabilities for more sophisticated grid structures.

matplotlib polar 2d histogram

I am trying to plot some histogrammed data on a polar axis but it wont seem to work properly. An example is below, I use the custom projection found How to make the angles in a matplotlib polar plot go clockwise with 0° at the top? it works for a scatter plot so I think my problem is with the histogram function. This has been driving me nuts all day, does anyone know what I am doing wrong...........
import random
import numpy as np
import matplotlib.pyplot as plt
baz = np.zeros((20))
freq = np.zeros((20))
pwr = np.zeros((20))
for x in range(20):
baz[x] = random.randint(20,25)*10
freq[x] = random.randint(1,10)*10
pwr[x] = random.randint(-10,-1)*10
baz = baz*np.pi/180.
abins = np.linspace(0,2*np.pi,360) # 0 to 360 in steps of 360/N.
sbins = np.linspace(1, 100)
H, xedges, yedges = np.histogram2d(baz, freq, bins=(abins,sbins), weights=pwr)
plt.figure(figsize=(14,14))
plt.subplot(1, 1, 1, projection='northpolar')
#plt.scatter(baz, freq)
plt.pcolormesh(H)
plt.show()
Your code works if you explicitly pass a mgrid (with similar characteristics than your a bins and sbins) to the pcolormesh command.
Below is an example inspired by your code:
import matplotlib.pyplot as plt
import numpy as np
#Generate the data
size = 200
baz = 10*np.random.randint(20, 25, size)*np.pi/180.
freq = 10*np.random.randint(1, 10, size)
pwr = 10*np.random.randint(-10, -1, size)
abins = np.linspace(0, 2*np.pi, 360) # 0 to 360 in steps of 360/N.
sbins = np.linspace(1, 100, 50)
H, xedges, yedges = np.histogram2d(baz, freq, bins=(abins,sbins), weights=pwr)
#Grid to plot your data on using pcolormesh
theta, r = np.mgrid[0:2*np.pi:360j, 1:100:50j]
fig, ax = plt.subplots(figsize=(14,14), subplot_kw=dict(projection='northpolar'))
ax.pcolormesh(theta, r, H)
ax.set_yticklabels([]) #remove yticklabels
plt.show()

Weird "zero ticks" on matplotlib subplot y-axis

I'm creating a plot consisting of several subplots in matplotlib, like this one:
But for some reason, I get weird Zeros on the y-axis (actually on both sides of the plot):
They don't seem to be ticks, since the ax1.get_yaxis().set_ticks([]) statement does not affect them.
Any ideas why I get these and how I can get rid of them?
import matplotlib.pyplot as plt
from pylab import *
import numpy as np
subplots_adjust(hspace=0.000)
groups = ['01', '03', '05', '07']
for i in range(len(groups)):
x = np.linspace(0, 2*np.pi,400)
y = np.sin(x**2)
ax1 = subplot(len(groups),1,i+1)
ax1.scatter(x, y, s=20, c='b', marker='o')
plt.xlim(xmin=0,xmax=1)
ax1.get_yaxis().set_ticks([])
plt.show()
plt.close()
Thank you for any help!
These are just leftovers from the x ticks at 0.0 and 1.0:
import matplotlib.pyplot as plt
#from pylab import * # don't do it, btw
import numpy as np
groups = ['01' , '03', '05', '07']
fig = plt.figure()
ax = []
for i in range(len(groups)):
ax.append( fig.add_subplot( len(groups), 1, i+1 ) )
fig.subplots_adjust(hspace=0.000)
for i in range(len(groups)):
x = np.linspace(0, 2*np.pi,400)
y = np.sin(x**2)
ax[i] = plt.subplot(len(groups),1,i+1)
ax[i].scatter(x, y, s=20, c='b', marker='o')
ax[i].get_yaxis().set_ticks([])
ax[i].set_xlim([0.001,0.9999]) # <<<<========== here
plt.show()