I'm trying to reproduce this plot in python with little luck:
It's a simple number density contour currently done in SuperMongo. I'd like to drop it in favor of Python but the closest I can get is:
which is by using hexbin(). How could I go about getting the python plot to resemble the SuperMongo one? I don't have enough rep to post images, sorry for the links. Thanks for your time!
Example simple contour plot from a fellow SuperMongo => python sufferer:
import numpy as np
from matplotlib.colors import LogNorm
from matplotlib import pyplot as plt
plt.interactive(True)
fig=plt.figure(1)
plt.clf()
# generate input data; you already have that
x1 = np.random.normal(0,10,100000)
y1 = np.random.normal(0,7,100000)/10.
x2 = np.random.normal(-15,7,100000)
y2 = np.random.normal(-10,10,100000)/10.
x=np.concatenate([x1,x2])
y=np.concatenate([y1,y2])
# calculate the 2D density of the data given
counts,xbins,ybins=np.histogram2d(x,y,bins=100,normed=LogNorm())
# make the contour plot
plt.contour(counts.transpose(),extent=[xbins.min(),xbins.max(),
ybins.min(),ybins.max()],linewidths=3,colors='black',
linestyles='solid')
plt.show()
produces a nice contour plot.
The contour function offers a lot of fancy adjustments, for example let's set the levels by hand:
plt.clf()
mylevels=[1.e-4, 1.e-3, 1.e-2]
plt.contour(counts.transpose(),mylevels,extent=[xbins.min(),xbins.max(),
ybins.min(),ybins.max()],linewidths=3,colors='black',
linestyles='solid')
plt.show()
producing this plot:
And finally, in SM one can do contour plots on linear and log scales, so I spent a little time trying to figure out how to do this in matplotlib. Here is an example when the y points need to be plotted on the log scale and the x points still on the linear scale:
plt.clf()
# this is our new data which ought to be plotted on the log scale
ynew=10**y
# but the binning needs to be done in linear space
counts,xbins,ybins=np.histogram2d(x,y,bins=100,normed=LogNorm())
mylevels=[1.e-4,1.e-3,1.e-2]
# and the plotting needs to be done in the data (i.e., exponential) space
plt.contour(xbins[:-1],10**ybins[:-1],counts.transpose(),mylevels,
extent=[xbins.min(),xbins.max(),ybins.min(),ybins.max()],
linewidths=3,colors='black',linestyles='solid')
plt.yscale('log')
plt.show()
This produces a plot which looks very similar to the linear one, but with a nice vertical log axis, which is what was intended:
Have you checked out matplotlib's contour plot?
Unfortunately I couldn't view yours images. Do you mean something like this? It was done by MathGL -- GPL plotting library, which have Python interface too. And you can use arbitrary data arrays as input (including numpy's one).
You can use numpy.histogram2d to get a number density distribution of your array.
Try this example:
http://micropore.wordpress.com/2011/10/01/2d-density-plot-or-2d-histogram/
Related
I am looking to plot some density maps from some grid-like data:
X,Y,Z = np.mgrids[-5:5:50j, -5:5:50j, -5:5:50j]
rho = np.random.rand(50,50,50) #for the sake of argument
I am interested in producing an interpolated density plot as shown below, from Mathematica here, using Python.
Is there any solution in Matplotlib or another plotting suite for this sort of plot?
To be clear, I do not want a scatterplot of coloured points, which is not suitable the plot I am trying to make. I would like a 3D interpolated density plot, as shown below.
Plotly
Plotly Approach from https://plotly.com/python/3d-volume-plots/ uses np.mgrid
import plotly.graph_objects as go
import numpy as np
X, Y, Z = np.mgrid[-8:8:40j, -8:8:40j, -8:8:40j]
values = np.sin(X*Y*Z) / (X*Y*Z)
fig = go.Figure(data=go.Volume(
x=X.flatten(),
y=Y.flatten(),
z=Z.flatten(),
value=values.flatten(),
isomin=0.1,
isomax=0.8,
opacity=0.1, # needs to be small to see through all surfaces
surface_count=17, # needs to be a large number for good volume rendering
))
fig.show()
Pyvista
Volume Rendering example:
https://docs.pyvista.org/examples/02-plot/volume.html#sphx-glr-examples-02-plot-volume-py
3D-interpolation code you might need with pyvista:
interpolate 3D volume with numpy and or scipy
I am working on a visualization script for a linear algebra class at the university and I am trying to show multiple vectors using the quiver function in python. I am trying to plot vectors coming from a 2x2 matrix in one quiver function, however, now that I am trying to label them I would like to access each vector individually.
import numpy as np
import matplotlib.pyplot as plt
A = np.array([[1,3], [2,2]])
# create figure
fig = plt.figure()
# creates variable containing current figure
ax = fig.gca()
baseArrow = ax.quiver(*origin, A[0,:], A[1,:], color=['r','g']', angles='xy', scale_units='xy', scale=1)
ax.quiverkey(baseArrow,.85,.85,0.8,'i-hat',labelcolor='k',labelpos='S', coordinates = 'figure')
# display grid
plt.grid()
# display figure
plt.show()
This alows me to label the first vector with the respective color (red). Now what I would like to do is label the second vector in green with a different label?
Maybe something like:
ax.quiverkey(baseArrow**[2]**,.85,.85,0.8,'i-hat',labelcolor='k',labelpos='S', coordinates = 'figure')
Is there any way to pull out each vector by itself or would it be better to plot them individually instead of as a vector? I looked at the following question but it doesn't really solve my issue. Matplotlib Quiver plot matching key label color with arrow color
My feeling is that the quiver function is better suited/intended to plot numerous vectors as you would find in a graph depicting magnetic forces, vortices (sic) or gradients (see meshgrid for example). And it's API reflects that, in that it accepts end and start coordinates separately: i.e. you need to split the components of your vectors as you have done above.
May I suggest you look into the plot or arrow functions which will give you greater control over your visualization (e.g. vector-independent labels) and will also provide greater clarity in your code, as you will be able to declare vectors (as np.arrays of course) and use them directly.
Finally note that you can obtain fig and ax in one call: fib, ax = plt.subplots().
Hope this helps!
I believe the fix to this will be relatively simple, but I can't seem to figure out how to convolve a scatter plot that I've plotted in python.
I have 2 data arrays, one of galactic latitudes and one of galactic longitudes, and I've plotted them with a hammer projection to represent a distribution of stars in galactic coordinates.
Now, I want to use boxcar smoothing to smooth the plot with 15 degree boxes.
I have tried using astropy.convolution with convolve and Box2DKernel, but I can't seem to make it work.
I've also looked at examples from http://docs.astropy.org/en/stable/convolution/kernels.html
but I don't understand how to translate their examples to what I need to do. They seem to be plotting a 2D function and smoothing that. Can I not convolve a plot and bin up the points by where they are on the graph? The only thing that I've gotten to display anything produces a straight line and I don't understand why. I'm very new to python so this has been giving me a lot of trouble.
This is the code that I have so far:
This plots the two arrays into a hammer projection:
from astropy import units as u
import astropy.coordinates as coord
glat = coord.Angle(pos_data['GLAT']*u.degree)
glon = coord.Angle(pos_data['GLON']*u.degree)
glon= glon.wrap_at(180*u.degree)
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,12))
ax = fig.add_subplot(211, projection="hammer")
ax.scatter(glon.radian, glat.radian)
ax.grid(True)
This is my attempt at convolving the data:
from astropy.convolution import convolve, Box2DKernel
data = [glon, glat]
kernel = Box2DKernel(10)
smoothed = convolve(data, kernel)
ax = fig.add_subplot(212, projection="hammer")
ax.scatter(smoothed[0]*u.radian, smoothed[1]*u.radian)
ax.grid(True)
Like I said, it's just one of many attempts that ended up giving something instead of an error, but I'm not sure that I'm using the function correctly at all. I'm not sure (or I don't think) that I can create "data" the way that I did, but any other combination of arrays or convolving each as a 1D array didn't work either.
Any ideas would be really helpful, thanks.
It seems like you're looking for Kernel Density Estimation, which is a way of turning individual measurements of spatial point patterns into a continuous distribution. I happen to prefer the scikit-learn implementation. You can then use the basemap package to do your plotting. The following code should be adaptable to your situation, where ra and dec are arrays of your stars' Right Ascension and Declination (you'll have to be careful about radians vs degrees here):
from sklearn.neighbors import KernelDensity
from sklearn.grid_search import GridSearchCV
data = np.column_stack((ra, dec))
# use a tophat/boxcar kernel and a haversine (spherical) metric
p = {'bandwidth': np.logspace(-1, 1, 20), 'kernel'='tophat',
'metric'='haversine'}
grid = GridSearchCV(KernelDensity(), params)
grid.fit(data)
Then you should be able to define a meshgrid over which to evaluate your KDE, and then plot it using imshow/pcolormesh/something else over a Hammer projection (see here or here)
How do I create a contour plot with a symlog (symmetrical log) scale for the contours. i.e. a log scale that shows both negative and positive values.
One possibility would be to work off of this example:
http://matplotlib.org/examples/pylab_examples/contourf_log.html
Which gives this recipe for a log scale:
from matplotlib import pyplot, ticker
cs = pyplot.contourf(X, Y, z, locator=ticker.LogLocator())
However, this doesn't allow for negative values. There is a ticker.SymmetricalLogLocator(), which may be the solution, but it doesn't seem to have much documentation.
EDIT:
To clarify (since requesting negative values on a log scale may sound nonsensical), what I want is the same as the "symlog" scale provided on matplotlib axes. The plot below, (taken from another stack exchange post), shows symlog on the x-axis. It is a "log" scale, but handles negative values in a way that is clear to the viewer.
I want the same sort of scaling, but for the colorscale on contour or contourf.
I stumbled across this thread trying to do the same thing, i.e plotting a large range of values in both the positive and negative direction. In addition I wanted to have a granularity as fine as in imshow.
It turns out you can have that using "ticker.MaxNLocator(nbins)" where nbins can be set high to have a fine granularity, e.g. set nbins to 100.
I also wanted to have a nice Latex style ticker formatting, for which I found a solution on StackOverflow a while ago.
I will just post this code snippet here from one of the classes it is part of so that anyone who might want can get the basic idea about how it's working. I use this solution to generate multiple plots as shown in the image below.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
# function for nice Latex style tick formatting
# copied from
# http://stackoverflow.com/questions/25983218/
# scientific-notation-colorbar-in-matplotlib
# output formating for colorbar in 2D plots
def fmt(x, pos):
a, b = '{:.2e}'.format(x).split('e')
b = int(b)
return r'${} \times 10^{{{}}}$'.format(a, b)
# A confourf function I use inside one of my classes
# mainly interesting are the "plot" and "cbar" lines
def Make2DSubPlot(self, posIdent, timeIdx,typeIdx):
plt.subplot(posIdent)
y = self.radPos
x = self.axPos
z = self.fieldList[timeIdx][typeIdx]
plot = plt.contourf(x, y, z, locator=ticker.MaxNLocator(100), \
aspect='auto',origin='lower')
cbar = plt.colorbar(plot, orientation='vertical', \
format=ticker.FuncFormatter(fmt))
cbar.ax.set_ylabel(self.labelList[typeIdx])
plt.xlabel(self.labelList[self.iax])
plt.ylabel(self.labelList[self.iax])
cI previously posted this over at code review, but moved it over here as I was told it is more fitting.
Basically, I want to create a colorplot of some irregularly sampled data. I've had some success with the interpolation using matplotlib.mlab.griddata. When I plot the interpolated data (using matplotlib.pyplot.imshow) however, the edges of the domain appear to be left blank. This gets better if I increase the grid density (increase N in the code) but doesn't solve the problem.
I've attached my code and would like to upload an image of the plot I can generate, but am still lacking the reputation to post an image ;)
edit: That has changed now, uploaded the plot after the changes proposed by Ajean:
. Can someone help me out as to what is going wrong?
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.mlab import griddata
# Generate Data
X=np.random.random(100)
Y=2*np.random.random(100)-1
Z=X*Y
# Interpolation
N=100j
extent=(0,1,-1,1)
xs,ys = np.mgrid[extent[0]:extent[1]:N, extent[2]:extent[3]:N]
resampled=griddata(X,Y,Z,xs,ys,interp='nn')
#Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlabel('X')
ax.set_ylabel('Y')
cplot=ax.imshow(resampled.T,extent=extent)
ticks=np.linspace(-1,1,11)
cbar=fig.colorbar(magplot,ticks=ticks,orientation='vertical')
cbar.set_label('Value', labelpad=20,rotation=270,size=16)
ax.scatter(X,Y,c='r')
It is because your calls to random don't provide you with any values at the boundary corners, therefore there is nothing to interpolate with. If you change X and Y definitions to
# Just include the four corners
X=np.concatenate([np.random.random(100),[0,0,1,1]])
Y=np.concatenate([2*np.random.random(100)-1,[-1,1,1,-1]])
You'll fill in the whole thing.