mplot3d: Hiding a line plot `plot()` under a `plot_surface()` - matplotlib

Edit: the problem I describe here no longer shows with current versions of matplotlib (2.1.1, edit made on 10 Sep 2019): most certainly a bug that has been fixed since then
I want to have a line plot (drawn with Axis.plot()) that is partially covered by the surface generated by Axis.plot_surface(). I wrote the following script:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
resolution = 100
ax = plt.gca(projection="3d")
x, y = np.meshgrid( np.linspace(-1.0, 1.0, resolution) ,
np.linspace(-1.0, 1.0, resolution) )
phi = (1.0 - x)*(1.0 - y) / 4.0
ax.plot([-1.0,1.0], [-1.0,1.0], [0.0,0.0], color="red")
ax.plot_surface(x, y, phi, linewidth=0, antialiased=False)
plt.show()
and made sure to have the call to plot() before the one to plot_surface(). Nevertheless, it seems that the line plot always has the highest "zindex" and gets plotted over the surface. Here is what I obtain:
Here is what I would like to have instead:
How do I achieve this result? (Without using Gimp…)

I changed.
ax.plot_surface(x, y, phi, linewidth=0, antialiased=False)
with:
ax.plot_surface(x, y, phi, linewidth=0, antialiased=True)
and then I saw the whole red line
It shows the plot with red line

Related

Warping Matplotlib/Seaborn Scatter Plot into Parallelogram

I have a 2D scatterplot (in either matplotlib or seaborn) and an angle e.g. 64 degrees. I want to plot a warped version of this scatter plot where the x-axis of the first plot is held fixed but the second axis is warped such that the y-axis of the first plot is now at the given angle with the x-axis of the new plot (i.e. 64 degrees). How can I do this?
In other words, I want to take the original scatter plot and "push" the y-axis to the right to form a parallelogram-like plot where the angle between the old y axis and the old/new x-axis is the given angle.
Here is an adaption of an old tutorial example:
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
import mpl_toolkits.axisartist.floating_axes as floating_axes
import numpy as np
fig = plt.figure()
skewed_transform = Affine2D().skew_deg(90 - 64, 0)
grid_helper = floating_axes.GridHelperCurveLinear(skewed_transform, extremes=(-0.5, 1.5, -0.5, 1.5))
skewed_ax = floating_axes.FloatingSubplot(fig, 111, grid_helper=grid_helper)
skewed_ax.set_facecolor('0.95') # light grey background
skewed_ax.axis["top"].set_visible(False)
skewed_ax.axis["right"].set_visible(False)
fig.add_subplot(skewed_ax)
x, y = np.random.rand(2, 100) # random point in a square of [0,1]x[0,1]
skewed_ax.scatter(x, y, transform=skewed_transform + skewed_ax.transData)
plt.show()

Is it possible to do draw plot in matplotlib where all points are linked to the x axis?

I am trying to find a way in matplotlib to draw a lineplot, except that I don't want to draw a line between points. Instead I want to draw a perpendicular line between each of my points and the x axis.
When I do a standard plot, I obtain the following :
import numpy as np
import matplotlib.pyplot as plt
data = np.array([0,1,3,2,3,1,4])
plt.plot(data)
plt.xlim([-0.2,6.2])
plt.ylim([-0.2,5])
Instead I want to obtain the following :
Any ideas how to do this ?
Thanks
There are two other options apart from stem and bar chart is the following using vlines() and LineCollection()
Option 1 -- Using vlines()
for x, y in enumerate(data):
plt.vlines(x=x, ymin=0, ymax=y, color='r')
Or in a single line without using loops
plt.vlines(x=range(data.size), ymin=0, ymax=data, color='r')
Option 2 -- Using LineCollection()
from matplotlib.collections import LineCollection
lines = [[(x, 0), (x, y)] for x, y in enumerate(data)]
linesCol = LineCollection(lines, linewidths=3, color='r')
fig, ax = plt.subplots()
ax.add_collection(linesCol)
plt.scatter(range(len(data)), data, s=0)

show origin axis (x,y) in matplotlib plot

I have following simple plot, and I would like to display the origin axis (x, y). I already have grid, but I need the x, y axis to be emphasized.
this is my code:
x = linspace(0.2,10,100)
plot(x, 1/x)
plot(x, log(x))
axis('equal')
grid()
I have seen this question. The accepted answer suggests to use "Axis spine" and just links to some example. The example is however too complicated, using subplots. I am unable to figure out, how to use "Axis spine" in my simple example.
Using subplots is not too complicated, the spines might be.
Dumb, simple way:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0.2,10,100)
fig, ax = plt.subplots()
ax.plot(x, 1/x)
ax.plot(x, np.log(x))
ax.set_aspect('equal')
ax.grid(True, which='both')
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')
And I get:
(you can't see the vertical axis since the lower x-limit is zero.)
Alternative using simple spines
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0.2,10,100)
fig, ax = plt.subplots()
ax.plot(x, 1/x)
ax.plot(x, np.log(x))
ax.set_aspect('equal')
ax.grid(True, which='both')
# set the x-spine (see below for more info on `set_position`)
ax.spines['left'].set_position('zero')
# turn off the right spine/ticks
ax.spines['right'].set_color('none')
ax.yaxis.tick_left()
# set the y-spine
ax.spines['bottom'].set_position('zero')
# turn off the top spine/ticks
ax.spines['top'].set_color('none')
ax.xaxis.tick_bottom()
Alternative using seaborn (my favorite)
import numpy as np
import matplotlib.pyplot as plt
import seaborn
seaborn.set(style='ticks')
x = np.linspace(0.2,10,100)
fig, ax = plt.subplots()
ax.plot(x, 1/x)
ax.plot(x, np.log(x))
ax.set_aspect('equal')
ax.grid(True, which='both')
seaborn.despine(ax=ax, offset=0) # the important part here
Using the set_position method of a spine
Here are the docs for a the set_position method of spines:
Spine position is specified by a 2 tuple of (position type, amount).
The position types are:
'outward' : place the spine out from the data area by the specified number of points. (Negative values specify placing the
spine inward.)
'axes' : place the spine at the specified Axes coordinate (from
0.0-1.0).
'data' : place the spine at the specified data coordinate.
Additionally, shorthand notations define a special positions:
'center' -> ('axes',0.5)
'zero' -> ('data', 0.0)
So you can place, say the left spine anywhere with:
ax.spines['left'].set_position((system, poisition))
where system is 'outward', 'axes', or 'data' and position in the place in that coordinate system.
Some time has passed since this question was asked. With Matplotlib 3.6.2 it looks like this works:
plt.axhline(0, color='black', linewidth=.5)
plt.axvline(0, color='black', linewidth=.5)
and there are other options.
Let me answer to this (rather old) question for those who will search for it as I just did. Although it suggested working solutions, I consider the (only) provided answer as way too complex, when it comes to such a simple situation like that described in the question (note: this method requires you to specify all axes endpoints).
I found a simple working solution in one of the first tutorials on matplotlib's pyplot. It is sufficient to add the following line after the creation of the plot
plt.axis([xmin, xmax, ymin, ymax])
as in the following example:
from matplotlib import pyplot as plt
xs = [1,2,3,4,5]
ys = [3,5,1,2,4]
plt.scatter(xs, ys)
plt.axis([0,6,0,6]) #this line does the job
plt.show()
which produces the following result:

Why does logarithmic scatter axis not start at zero?

I'm generating a scatter plot in matplotlib. Everything works fine if I use linear scales.
But since I'm mainly interested in the lower values, I thought I'd use logarithmic scaling. However, even though I have set my x-axis limits explicitly to (0,1), the axis starts at 0.1, so i miss everything below that!
Why does the logarithmic axis not start at zero, and how can I force it to?
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,1,100)
y = np.random.randint(1000, size=100)
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x, y)
ax.set_xlim(0,1.2)
ax.set_ylim(0,1000)
ax.set_yscale('log')
ax.set_xscale('log')
ax.yaxis.set_major_formatter(plt.FormatStrFormatter('%1.0f'))
ax.xaxis.set_major_formatter(plt.FormatStrFormatter('%.1f'))
ax.xaxis.set_minor_formatter(plt.FormatStrFormatter('%.1f'))
# this red line at x = 0.1
ax.axvline(x=0.1,color='r')
plt.show()
Any help is greatly appreciated!
Usually logarithmic axes never start at zero because there is no "good" value for log(0) on the x-axis, because log(0)==x only for x->-infinity.

Unfilled bar plot in matplotlib

With histograms, there's a simple built-in option histtype='step'. How do I make a bar plot in the same style?
[adding answer after reading the comments]
Set the optional keyword to be fill=False for bar plots:
import matplotlib.pyplot as plt
plt.bar(bins[:5], counts[:5], fill=False, width=60) # <- this is the line
plt.title("Number of nodes with output at timestep")
plt.xlabel("Node count")
plt.ylabel("Timestep (s)")
will give:
Or use plt.plot with the keyword ls='steps' :
plt.plot(bins[-100:], counts[-100:], ls='steps')
plt.title("Number of nodes with output at timestep")
plt.xlabel("Node count")
plt.ylabel("Timestep (s)")
Although OP linked to a post that answered a slightly different question relating to histogram step plots, here is a solution for anyone passing through here who is specifically trying to turn off the face color in pyplot.bar bar plots:
import matplotlib.pyplot as plt
import numpy as np
# create x coords for the bar plot
x = np.linspace(1, 10, 10)
# cook up some random bar heights -- exact results may vary :-P
y = np.random.randn(10)
z = np.random.randn(10) * 2
# plot bars with face color off
plt.bar(x-0.2, y, width=0.4, edgecolor='purple', color='None')
plt.bar(x+0.2, z, width=0.4, edgecolor='darkorange', color='None')
plt.show()
Note that bar edges have settable matplotlib.lines.Line2D attributes, such as linewidth, linestyle, alpha, et cetera:
plt.bar(x-0.2, y, width=0.4, edgecolor='purple', color='None',
linewidth=0.75, linestyle='--')
plt.bar(x+0.2, z, width=0.4, edgecolor='darkorange', color='None',
linewidth=1.5, linestyle='-.')
plt.show()
I saw you found an answer on this other topic, nonetheless I have the feeling matplotlib.pyplot.step does the job too and is more direct (see here).
Edit: as requested, some sample code to illustrate usage of plt.step
import matplotlib.pyplot as plt
plt.step(list(range(10)),list(range(5))+list(range(5)))