Plotting 3-D surfaces and lines with perspective - python

I'm trying to plot a line through a 3-D surface as a means of indicating the axis. However, this only results in the line being plotted entirely on top of or beneath the surface--changing the zorder does not solve this.
What I'm looking for is for the line to appear as if it were piercing through the surface
My code and output are below:
fig = plt.figure(figsize=(9,9))
ax = plt.axes(projection='3d')
ax.plot_surface(X,Z,Y,
linewidth=0,
cmap=cm.jet,
facecolors=cm.jet(r_3d/max(abs(r_3d.flatten()))),
edgecolor='none',
shade=False,
antialiased=False)
ax.plot([0,0],[-0.3,0.3],[0,0],linewidth=2,c='k')
Example of line plotted on top of surface
Hand drawn example of my desired output

I think you can solve this with zorder (example here), though I have not tried specifically with a 3d plot. zorder changes the plotting order, or essentially the depth at which specific items are plotted. Large z orders plot on top and small ones plot in the back, so if you make the 3d item a z order of 1 and the line as z order zero that should work.

Related

Matplotlib: plot arbitrary vectors on polar axes

There are previous questions about quiver plots on polar axes in matplotlib, however they concern vector fields. I'm interested in drawing arbitrary vectors on polar axes. If there is a genuine duplicate, please link it.
I'm writing some software which concerns a circular world. I'm plotting an agent's trajectory from the centre of a circular arena to the edge. This is visualised by drawing a vector from the centre of the circle to the edge. I'm trying to use matplotlib's quiver plot to plot vectors on a set of polar axes. Here's a minimum working example:
import matplotlib.pyplot as plt
import numpy as np
if __name__ == '__main__':
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
# Plot origin (agent's start point)
ax.plot(0, 0, color='black', marker='o', markersize=5)
# Plot agent's path
ax.quiver((0, 0), (0, 1), color='black')
# Example of where (0, 1) should be
ax.plot(0, 1, color='black', marker='o', markersize=5)
# Plot configuration
ax.set_rticks([])
ax.set_rmin(0)
ax.set_rmax(1)
ax.set_thetalim(-np.pi, np.pi)
ax.set_xticks(np.linspace(np.pi, -np.pi, 4, endpoint=False))
ax.grid(False)
ax.set_theta_direction(-1)
ax.set_theta_zero_location("N")
plt.show()
If you run the code, you get this plot
The plot shows the origin plotted correctly, an example point at (0, 1) to show where the vector should end, then the vector itself which appears far too short (though the direction is correct). From the docs, I understand that quiver takes cartesian coordinates (x,y) denoting the start point of the vector and (u,v) denoting the vector's direction. In my previous experience with quiver (u,v) essentially denotes where the vector's tip will be, so in this case we'd expect the vector to be drawn from (0,0) to (0,1) which isn't the case and I don't know why.
In short, I want to be able to draw arbitrary vectors on a set of polar axes and quiver isn't working as I expected. Three questions:
Is my code actually sensible given my goal? I want to draw a unit vector from the origin to the edge of the polar plot.
Am I completely misunderstanding how to use quiver?
How can I draw arbitrary vectors on polar axes in matplotlib? I know about arrow and I'm going to give that a try though initial attempts were unsuccessful.
Short of using a standard plot and just defining my own polar system within it I'm completely stumped.
You did not specify u and v in ax.quiver(x,y,u,v). To make sure the arrow is 1 unit long you will need to set the scale und units as well.
ax.quiver(0,0,0,1, color='black', angles="xy", scale_units='xy', scale=1.)

How to overlay scatter plot on top of a line plot using matplotlib?

So I have a line plot, and I want to add markers on only some of the points along the plot (I have detected the peaks in the plot and want to mark them). When I plot without the peaks labelled it works as it should, and when I plot the peaks alone it seems to plot them properly, but when I try to plot them on the same plot, the line plot disappears over most of the graph and seems to maybe have become compressed to the side of the plot, if that makes any sense?
Here is my code without the peaks plotted and the resulting graph:
def plotPeaks(file):
indices, powerSums, times=detectPeaks(file)
plt.figure(figsize=(100, 10))
plt.plot(times, powerSums)
Plot without peaks marked
Then when I add the code that should show the peaks, which occur at x-values corresponding to the values stored in the indices, I get this:
def plotPeaks(file):
indices, powerSums, times=detectPeaks(file)
plt.figure(figsize=(100, 10))
plt.plot(times, powerSums)
for i in indices:
plt.scatter(i, powerSums[i], marker='o')
Plot with peaks marked
Am I missing something obvious, or is this a glitch that someone has a solution for?
Assuming indices stores indices of times, this should be the last line.
plt.scatter(times[i], powerSums[i], marker='o')

Move spines in matplotlib 3d plot?

I'm trying to move the spines in a 3D matplotlib axes object.
This seems like a really simple issue, but I have not found any questions/answers that address this directly. I've included a list of my research on this topic at the bottom of this question.
I can set the position of the spines in matplotlib 2D plots. The following code:
import matplotlib.pyplot as plt, numpy as np
fig, axes = plt.subplots(1, 2)
r, theta = 1, np.linspace(0, 2*np.pi, 100)
x, y = r*np.cos(theta), r*np.sin(theta)
for ax in axes: # plot the same data on both axes
ax.plot(x, y)
ax.set_aspect("equal")
for spine in ax.spines.values(): # adjust spines on last active axis
spine.set_position(("data", 0))
produces:
However, when I try the same thing with a 3D axis...
z = np.zeros(x.shape) # exciting stuff
fig = plt.figure()
for i in range(2): # create two 3D subplots
ax = plt.subplot(1,2,i+1, projection="3d", aspect="equal")
plt.plot(x, y, z)
for spine in ax.spines.values(): # adjust spines on last active axis
spine.set_position(("data", 0))
the above code gives me:
I.e. no effect, even though the code still runs. Also, for the 3D axes, ax.spines looks like:
OrderedDict([('left', <matplotlib.spines.Spine at 0x120857b8>),
('right', <matplotlib.spines.Spine at 0xfd648d0>),
('bottom', <matplotlib.spines.Spine at 0xe89e4e0>),
('top', <matplotlib.spines.Spine at 0xe89eef0>)])
I'm not sure what "left", "right", "bottom", "top" refer to in the context of a 3D axis. I've tried changing other properties like colour of the spines; no luck there either. How can I get hold of the actual x, y, z spines on the axes?
Research:
searching "matplotlib spines 3d" in stackoverflow gives 5 results (including this question) at the time of writing.
The mplot3d documentation doesn't mention spines at all.
This question shows how to set the pane colour with ax.w_xaxis.set_pane_color(), but there is no similar ax.w_zaxis.set_spine... method.
This question shows how to set the spine colour using ax.w_zaxis.line.set_color(). I thought about making a horrible workaround to set ax.w_zaxis.line.set_data manually, but it only has x and y data; no z! Even the x and y axes don't have z data.
There seems to be no obvious way to do this at the moment. Setting the spines when the axis projection is 3D is not implemented. However, there is a small hack here.
The ax.spines setting is for 2D rendering. When you set projection=3d in the initialization of the figure, certain 2D properties (like ax.spines, etc.) are ignored. It's why you don't get any response when you set the 2D spines.
The 3D figure axis line (the thick black line for each axis) locations are determined by the parameter ax.xaxis._axinfo['juggled'] (and similarly for y and z axes). This specifies which of the six outer boundaries of a 3D plot bounding box are plotted as thick black lines.
You can shift the position of the axis line for each of x,y,z axis by overwriting the juggled value, which specifies which axis lines are the main ones, as the following example for the x axis,
the default setting, ax.xaxis._axinfo['juggled'] = (1,0,2)
new setting, ax.xaxis._axinfo['juggled'] = (2,0,1)
The parameters for all the six outer boundaries are,

Adding lines and geometric shapes on matplotlib candlestick chart

I have made a candlestick currency chart on python using matplotlib.finance. Everything is working but I would like to add lines and shapes on the actual chart. When I was using normal type of chart in matplotlib. I would be doing:
plt.plot([xmin, xmax], [0.0005,0.0005], linewidth=3, color='purple')
To draw a horizontal line from xmin to xmax (to be defined) at the 0.0005 price level.But since I am using the method candlestick2_ohlc I don't really know how to proceed...
This is what I have:
This is what I am looking to get:
Also is it possible to draw and fill triangles?
Drawing segments
plt.plot([xmin, xmax], [ymin, ymax])
Drawing triangles
x = [x1, x2]
y = [y1, y2]
plt.fill(x,y)
Drawing polygons
x = [x1,...,xn]
y = [y1,...,yn]
plt.fill(x,y)
It's that easy!
The easiest way to draw a horizontal line is to use
plt.axhline(y=1.066)

Setting colour scale to log in a contour plot

I have an array A which I have plotted in a contour plot using X and Y as coordinate axes,
plt.contourf(X,Y,A)
Problem is, the values in A vary from 1 to a very large number such that the color scale doesn't show a plot. When I plot log(A), I get the following contour,
which is what I'm looking for. But I want to be able to view the values of the array A, instead of log(A), when I hover my cursor over a certain (X,Y) point. I already got an answer for how to do that, but how would I go about doing it while my colour scale remains log? Basically what I'm trying to do is to make the color scale follow a log pattern, but not the array values themselves.
Thanks a lot!
You can do this:
from matplotlib import colors
plt.contourf(X, Y, A, norm=colors.LogNorm())
plt.colorbar()
plt.show()
or
from matplotlib import ticker
plt.contourf(X, Y, A, locator=ticker.LogLocator())
plt.colorbar()
plt.show()
A similar question was already asked for log-scaling the colors in a scatter plot: A logarithmic colorbar in matplotlib scatter plot
As is it was indicated there, there is an article in matplotlibs documentation that describes norms of colormaps: http://matplotlib.org/devdocs/users/colormapnorms.html
Essentially, you can set the norm of your contourplot by adding the keyword , norm=matplotlib.colors.LogNorm()

Categories

Resources