I have a 64x360 Matrix of values belonging to radial and azimuthal coordinates. I want to visualize them in two plots: a cartesian and a polar plot.
I visualized the heatmap in cartesian coordinates using imshow():
import numpy as np
import matplotlib.pyplot as plt
P=np.loadtxt('Pdata.csv')
print np.shape(P)
plt.imshow(P)
plt.xlabel('radius')
plt.ylabel('theta')
plt.show()
This gives me the desired plot:
The same plot in polar coordinates was also pretty straigh forward using pcolor():
r=np.arange(0,np.shape(P)[1],1)
t=np.arange(0,np.shape(P)[0],1)
R,T = np.meshgrid(r,t)
fig = plt.figure()
ax = fig.add_subplot(111, polar = True)
ax.pcolor(T,R,P)
plt.show()
However, I am not really satisfied with the result:
The resolution of the plot seems to be pretty limited so that it's not possible to distinguish between angles with higher intensity and lower intensity, as it is in the cartesian plot. The whole solid angle seems to be divided into six or seven "cake wedges" only. Is there an easy and pythonic way to enhance the angular resolution?
Ok, I found out something. It works with:
t = np.radians(np.linspace(0, np.shape(P)[0],np.shape(P)[0]))
r = np.arange(0, np.shape(P)[1], 1)
Just as seen here: Polar contour plot in matplotlib - best (modern) way to do it?
Related
I am using matplotlib.pyplot and astropy to build a plot in galactic coordinates and my goal is to show the density of stars in the sky.
For that, the only data I have is a two-column table with the coordinates of the stars in Right Ascension (RA) and Declination (Dec).
Right now my code is doing the following:
import astropy.coordinates as coord
import matplotlib.pyplot as plt
import astropy.units as u
coordinates = coord.SkyCoord(ra=RA*u.deg, dec=DEC*u.deg)
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection="aitoff")
ax.plot(coordinates.galactic.l.wrap_at('180d').radian,
coordinates.galactic.b.radian, 'k.', alpha=0.01, ms=1)
ax.grid(True)
So for now I am basically using plt.plot to plot all datapoints (which in the case is half-million datapoints) using a very low alpha and symbol size and the plot looks like this:
However, this isn't the plot I want, as the colour scale quickly saturates.
My question is: Is there a way of making a similar plot but properly reflecting the density of datapoint in the z-axis (color)? For example, I want to be able of controling the color table for a given number-density of sources.
I've seen some answers to similar questions are available.
For example, this question (Plotting a heatmap in galactic coordinates) does a similar thing, but for a specific z-axis described by some data.
I am also aware of this question (How can I make a scatter plot colored by density in matplotlib?) and I tried each solution in this post, but they all failed since I am using a subplot which already has a projection.
Any ideas?
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 have a 3-D surface plot that shows x and y coordinates and depths. I also have a 2-D contourf plot with x and y coordinates and the filled contours at the different locations. If I know the depths at the coordinates in the contourf plot, is there a way I can show the contours on the 3-D surface plot?
I have created a 3-D surface plot using plotly with the code below:
import plotly.graph_objects as go
import oceansdb
import numpy as np
import matplotlib.pyplot as plt
Xa = np.linspace(29.005,29.405,200)
Ya = np.linspace(-93.6683,-93.2683,200)
db = oceansdb.ETOPO()
dcont = db['topography'].extract(lat=Xa, lon=Ya)
depth = dcont['height']
fig = go.Figure(data=[go.Surface(z=depth, x=Xa, y=Ya)])
fig.show()
Say my contourf plot can be created with the code below:
X = np.array([29.1,29.15,29.2,29.25])
Y = np.array([-93.5,-93.45,-93.4,-93.35])
r = np.array([0,0,0,2,3,0,0,6,7,8,9,1,9,0,0,0])
plt.figure()
plt.contourf(X,Y,r.reshape(len(X),len(Y)))
plt.show()
Assuming that the depth at each location can be determined using the oceansdb module, can I overlay the contour plot on the surface plot at the correct depth?
Using matplotlib the short answer is "yes", but there are two buts you have face:
Visualizing 3d data is difficult, and overlapping multiple datasets is more often than not confusing beyond the simplest cases
Matplotlib has a 2d renderer, so even though you can plot multiple objects in the same 3d figure, there will often be rendering artifacts (in particular, two objects can typically be either fully in front of or behind one another).
The key methods you need are Axes3D.contour or Axes3D.contourf. Here are these in action with your example data:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # this enables 3d axes
X = np.array([29.1,29.15,29.2,29.25])
Y = np.array([-93.5,-93.45,-93.4,-93.35])
r = np.array([0,0,0,2,3,0,0,6,7,8,9,1,9,0,0,0]).reshape(X.size, Y.size)
# plot your 2d contourf for reference
fig,ax = plt.subplots()
ax.contourf(X, Y, r)
# plot in 3d using contourf
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.contourf(X, Y, r)
# plot in 3d using contour
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.contour(X, Y, r)
plt.show()
Here's your 2d contourf plot:
Here's the 3d contourf version:
And here's the 3d contour version:
As you can see the difference between the latter two is that contourf also plots horizontal planes for each level (just like terraces), whereas contour only plots the level lines themselves.
Since repeated plots using the same axes will accumulate plots there's nothing stopping you from superimposing either of these 3d contour plots on your original surface. However, in line with my earlier warnings you'll have to watch if the contours are rendered correctly over the surface (under all view angles), and even if so the result might not be all that transparent for conveying information. I personally tend to find contourf much easier to comprehend than contour on a 3d plot, but I suspect that if we put these on top of full surface plots the latter will fare better.
I want to create a smooth cylinder using matplotlib/pyplot. I've adapted a tutorial online and produced the following minimal example:
from numpy import meshgrid,linspace,pi,sin,cos,shape
from matplotlib import pyplot
import matplotlib.tri as mtri
from mpl_toolkits.mplot3d import Axes3D
u,v = meshgrid(linspace(0,10,10),linspace(0,2*pi,20))
u = u.flatten()
v = v.flatten()
x = u
z = sin(v)
y = cos(v)
tri = mtri.Triangulation(u, v)
fig = pyplot.figure()
ax = fig.add_axes([0,0,1,1],projection='3d')
ax.plot_trisurf(x,y,z,triangles=tri.triangles,linewidth=0)
pyplot.show()
which produces a cylinder. I set linewidth=0 to remove the wireframe, however, there is now the "ghost" of the wireframe because the triangulation has (presumably) been spaced assuming the wireframe is there to fill in the gaps. This looks to be specific to plot_trisurf, because there are other 3d plotting examples (e.g., using plot_surface) which set linewidth=0 without these gaps showing up.
Doing an mtri.Triangulation?, it seems like it might not be possible to "perfectly" fill in the gaps, since it states
>Notes
> -----
> For a Triangulation to be valid it must not have duplicate points,
> triangles formed from colinear points, or overlapping triangles.
One partial solution is to just color the wireframe the same shade of blue, but after I've fixed this problem I also want to add a light source/shading on the surface, which would put me back at square one.
Is there a way to make this work? Or can someone suggest a different approach? Thanks for any help.
ax.plot_trisurf(x,y,z,triangles=tri.triangles,linewidth=0, antialiased=False)
I would like to plot a circle on an auto-scaled pyplot-generated graphic. When I run
ax.get_aspect()
hoping for a value with which I could manipulate the axes of a ellipse, pyplot returns:
auto
which is less than useful. What methods would you suggest for plotting a circle on a pyplot plot with unequal axes?
This question is more than one year old, but I too just had this question. I needed to add circles to a matplotlib plot and I wanted to be able to specify the circle's location in the plot using data coordinates, and I didn't want the circle radius to change with panning/zooming (or worse the circle turning into an ellipse).
The best and most simple solution that I've found is simply plot a curve with a single point and include a circle marker:
ax.plot(center_x,center_y,'bo',fillstyle='none',markersize=5)
which gives a nice, fixed-size blue circle with no fill!
It really does depend what you want it for.
The problem with defining a circle in data coordinates when aspect ratio is auto, is that you will be able to resize the figure (or its window), and the data scales will stretch nicely. Unfortunately, this would also mean that your circle is no longer a circle, but an ellipse.
There are several ways of addressing this. Firstly, and most simply, you could fix your aspect ratio and then put a circle on the plot in data coordinates:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.axes()
ax.set_aspect(1)
theta = np.linspace(-np.pi, np.pi, 200)
plt.plot(np.sin(theta), np.cos(theta))
plt.show()
With this, you will be able to zoom and pan around as per usual, but the shape will always be a circle.
If you just want to put a circle on a figure, independent of the data coordinates, such that panning and zooming of an axes did not effect the position and zoom on the circle, then you could do something like:
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.axes()
patch = mpatches.Circle((325, 245), 180, alpha=0.5, transform=None)
fig.artists.append(patch)
plt.show()
This is fairly advanced mpl, but even so, I think it is fairly readable.
HTH,
Building on #user3208430, if you want the circle to always appear at the same place in the axes (regardless of data ranges), you can position it using axes coordinates via transform:
ax.plot(.94, .94, 'ro', fillstyle='full', markersize=5, transform=ax.transAxes)
Where x and y are between [0 and 1]. This example places the marker in the upper right-hand corner of the axes.