Smoothed 2D histogram using matplotlib and imshow - python

I try to do a 2D histogram plot and to obtain a "smooth" picture by a sort of interpolation. Thus I do the following combining plt.hist2d and plt.imshow
import matplotlib.pyplot as plt
import numpy as np
data = np.loadtxt("parametre_optMC.dat", skiprows=50, usecols=(1,2))
h, x, y, p = plt.hist2d(data[:,0], data[:,1], bins = 20)
plt.imshow(h, origin = "lower", interpolation = "gaussian")
plt.savefig("test.pdf")
As you can see on the picture below, the two plots are superimposed and that is the problem for which I need some help
Adding clf works but I lose axes dimenions :
import matplotlib.pyplot as plt
import numpy as np
data = np.loadtxt("parametre_optMC.dat", skiprows=50, usecols=(1,2))
h, x, y, p = plt.hist2d(data[:,0], data[:,1], bins = 20)
plt.clf()
plt.imshow(h, origin = "lower", interpolation = "gaussian")
plt.savefig("test.pdf")

Perhaps it would be better to plot a kernel density estimate?
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
data = np.random.multivariate_normal([0, 0], [(1, .6), (.6, 1)], 100)
f, ax = plt.subplots(figsize=(7, 7))
sns.kdeplot(data, shade=True, ax=ax)

To your first question:
You need to clear data from a previous plot, putting the following before you plot should do this:
plt.clf()
plt.close()
To your second question:
To change the axis values I'd suggest the extent parameter (see this answer).
e.g. something like:
plt.imshow(h, origin = "lower", interpolation = "gaussian",extent=[-100,100,-75,75])

You need to add the 'extent' parameter to you imshow command. imshow accepts a grid of arbitrary values but does not know the dimensions.

Related

Python - setting arbitrary contour xy-ratio

I am reading the following discussion:
setting axis scale in matplotlib contour plot
From the discussion above, to get arbitrary ratio, we could use
plt.figure(figsize=(8,2))
# ...
plt.tight_layout()
However, this setting is for figure not for contourf.
I used the above codes in my codes
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import pandas as pd
import math
rm = pd.read_excel("test_3d.xlsx", header = None)
# find min values of noise
rec = np.shape(rm)
# grid
X = np.arange(1,rec[1]+1,1)
Y = np.arange(1,rec[0]+1,1)
x , y = np.meshgrid(X,Y)
# plots
plt.clf()
con = plt.contourf(x,y,rm, cmap=cm.jet)
plt.figure(figsize=(8,2))
plt.tight_layout()
plt.title('2457MHz')
plt.show()
The result I got is
The ratio of bottom plot is what I want; however, I use plt.figure(figsize=(8,2)), which is not for contourf. Therefore, I did not get the correct result.
Is there any way that I can plot arbitrary ratio for contourf?
Instead of setting the figsize, use Axes.set_aspect to change the aspect ratio of the contour plot's Axes:
fig, ax = plt.subplots()
ax.contourf(x, y, rm, cmap='viridis')
ax.set_aspect(0.25)
If you prefer to stick with the plt syntax, access the Axes using plt.gca:
plt.contourf(x, y, rm, cmap='viridis')
plt.gca().set_aspect(0.25)

Strange lines appear on pcolormesh in basemap when using a nonzero alpha value

When plotting data using pcolormesh on a basemap projection (or a cartopy projection) I notice strange lines appear when I set the alpha value to less than 1.
Example code:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
plt.clf()
dpp =1 # degrees per pixel
lons = np.arange(-180,180+dpp,dpp)
lats = -1*np.arange(-90,90+dpp,dpp)
m = Basemap(projection='robin',lon_0=0)
data = np.random.random((np.size(lats), np.size(lons)))
lons, lats = np.meshgrid(lons, lats)
x, y = m(lons, lats)
im = m.pcolormesh(x, y, x, latlon=False, cmap='RdBu')
#im = m.pcolormesh(lons, lats, data, latlon=True, cmap='RdBu')
m.colorbar(im)
plt.show()
The output shows strange lines appearing:
If I instead set alpha=1 the lines disappear and the behavior is as expected:
Any ideas on how to get pcolormesh to work with a nonzero alpha value?
Use pcolor instead of pcolormesh, it is a bit slower but it does a better job with handling rasterized output. Be sure to set snap = True, this will align the grid to the pixels.
Example
import numpy as np
import matplotlib.pyplot as plt
lons, lats = np.meshgrid(np.arange(-180,180), np.arange(90,-90,-1))
im = plt.pcolor(lons, lats, lons, cmap='RdBu', alpha=0.5, snap=True)
cbar = plt.colorbar(im)
cbar.set_alpha(0.5)
plt.show()
This should work with mpl_toolkits.basemap as well.
The lines in the colorbar are caused by the open issue #1188, as far as I know there is not a work around known which does not involve manually creating the colorbar.
Since it is a global map, I got it to work using imshow instead of pcolor or pcolormesh:
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
plt.clf()
lons, lats = np.meshgrid(np.arange(-180,180), np.arange(90,-90,-1))
im = ax.imshow(lons, transform=ccrs.PlateCarree(),cmap='RdBu', alpha=0.5, extent=[-180,180,-90,90])
cbar = plt.colorbar(im)
cbar.set_alpha(0.5)
plt.show()
There is still the issue with the colorbar however.

matplotlib contourf with extreme values

I have data I want to plot with extreme edge values, given below is a generic example:
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
Z = np.random.rand(100,100)
plt.contourf(Z, 100, cmap='RdGy', vmin=0, vmax=1)
plt.colorbar()
plt.show()
Using the above code I get this plot:
But if I change only one row of Z to contain extreme values it "dominates" the whole plot:
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
Z = np.random.rand(100,100)
Z[:1] *= 100
plt.contourf(Z, 100, cmap='RdGy', vmin=0, vmax=1)
plt.colorbar()
plt.show()
My question is so: In the second example, although I have extreme values, all the interesting things obviously happen in the range of 0 and 1, which is totally dominated by the multiplication I entered in the 1st row, even though I set vmin and vmax accordingly. How do I keep the data as is, while "focusing" on the 0-1 range? I don't really care what goes on in the first row, for all I care there can be a single color for the values 1-100.
Many Thanks.
This seems to be a known behavior, as reported in this GH issue.
A workaround (given in the issue comments) is to use an iterable for the levels arguments instead of relying on vmin and vmax.
Here is a code snippet to exhibit how vmin and vmax can be used with pcolormesh (as you said in the comment) but how to achieve a similar result with contourf.
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
def main():
fig, axs = plt.subplots(2)
Z = np.random.rand(100,100)
Z[:1] *= 100
cmap = plt.get_cmap("viridis")
p1 = axs[0].pcolormesh(Z, vmin=0., vmax=1, cmap=cmap)
fig.colorbar(p1, ax=axs[0])
p2 = axs[1].contourf(Z, levels=np.linspace(0, 1, 100), cmap=cmap)
fig.colorbar(p2, ax=axs[1], ticks=np.linspace(0, 1, 5))
plt.show()
if __name__ == '__main__':
main()

Matplotlib: transformation of variables for narrow orbit

I have an annoyingly narrow orbit in phase space that looks like this:
What kind of transformation of the variables can I do to get a nice circular orbit in this case?
My code is this:
import numpy as np
import matplotlib.pylab as plt
x,y = np.loadtxt("data.txt").T
plt.plot(x,y)
plt.show()
The data can be found here - link
I'm not sure if this is what you're after. What you can do is shift one of the two coordinates by the quarter of a circle and normalize to the other coordinate.
import numpy as np
import matplotlib.pylab as plt
x,y = np.loadtxt("data/orbit.txt").T
y = np.roll(y, len(y)//4)
y = (y-y.mean())*((x.max()-x.min())/(y.max()-y.min())) +y.mean()
fig, (ax, ax2) = plt.subplots(ncols=2)
ax.set_aspect("equal")
ax.plot(x,y)
t = np.linspace(0,2*np.pi, len(x))
ax2.plot(t,x-x.mean())
ax2.plot(t,y-y.mean())
plt.show()

Python matplotlib Colorfunction

I would like to use a ColorFunction similar to that in Mathematica for my plots in python.
In other words, I would like to call pyplot.plot(x, y, color=c), where c is a vector, defining the color of each data point.
Is there any way to achieve this using the matplotlib library?
To the best of my knowledge, there is no equivalent in Matplotlib, but we can get the similar result following two steps: draw points with varied colors and draw the line.
Here is a demo.
The source code,
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
import random
fig, ax = plt.subplots()
nrof_points = 100
x = np.linspace(0, 10, nrof_points)
y = np.sin(x)
colors = cm.rainbow(np.linspace(0, 1, nrof_points)) # generate a bunch of colors
# draw points
for idx, point in enumerate(zip(x, y)):
ax.plot(point[0], point[1], 'o', color=colors[idx], markersize=10)
# draw the line
ax.plot(x, y, 'k')
plt.grid()
plt.show()
While I agree with #SparkAndShine that there is no way to parameterize the color of one line, it is possible to color many lines to create a visual effect that is largely the same. This is at the heart of a demo in the MatPlotLib documentation. However, this demo is not the simplest implementation of this principle. Here is an alternate demo based on #SparkAndShine's response:
colored sine (can't post as image since I don't have the reputation)
Source code:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
fig, ax = plt.subplots()
nrof_points = 100
x = np.linspace(0, 10, nrof_points)
y = np.sin(x)
colors = cm.rainbow(np.linspace(0, 1, nrof_points)) # generate a bunch of colors
# draw points
for idx in range(0,np.shape(x)[0]-2,1):
ax.plot(x[idx:idx+1+1], y[idx:idx+1+1], color=colors[idx])
# add a grid and show
plt.grid()
plt.show()

Categories