show origin axis (x,y) in matplotlib plot - matplotlib

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:

Related

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)

Customize the axis label in seaborn jointplot

I seem to have got stuck at a relatively simple problem but couldn't fix it after searching for last hour and after lot of experimenting.
I have two numpy arrays x and y and I am using seaborn's jointplot to plot them:
sns.jointplot(x, y)
Now I want to label the xaxis and yaxis as "X-axis label" and "Y-axis label" respectively. If I use plt.xlabel, the labels goes to the marginal distribution. How can I make them appear on the joint axes?
sns.jointplot returns a JointGrid object, which gives you access to the matplotlib axes and you can then manipulate from there.
import seaborn as sns
import numpy as np
# example data
X = np.random.randn(1000,)
Y = 0.2 * np.random.randn(1000) + 0.5
h = sns.jointplot(X, Y)
# JointGrid has a convenience function
h.set_axis_labels('x', 'y', fontsize=16)
# or set labels via the axes objects
h.ax_joint.set_xlabel('new x label', fontweight='bold')
# also possible to manipulate the histogram plots this way, e.g.
h.ax_marg_y.grid('on') # with ugly consequences...
# labels appear outside of plot area, so auto-adjust
h.figure.tight_layout()
(The problem with your attempt is that functions such as plt.xlabel("text") operate on the current axis, which is not the central one in sns.jointplot; but the object-oriented interface is more specific as to what it will operate on).
Note that the last command uses the figure attribute of the JointGrid. The initial version of this answer used the simpler - but not object-oriented - approach via the matplotlib.pyplot interface.
To use the pyplot interface:
import matplotlib.pyplot as plt
plt.tight_layout()
Alternatively, you can specify the axes labels in a pandas DataFrame in the call to jointplot.
import pandas as pd
import seaborn as sns
x = ...
y = ...
data = pd.DataFrame({
'X-axis label': x,
'Y-axis label': y,
})
sns.jointplot(x='X-axis label', y='Y-axis label', data=data)

Tick labels displaying outside axis limits

Is there a way to automatically not display tick mark labels if they would protrude past the axis itself? For example, consider the following code
#!/usr/bin/python
import pylab as P, numpy as N, math as M
xvals=N.arange(-10,10,0.1)
yvals=[ M.sin(x) for x in xvals ]
P.plot( xvals, yvals )
P.show()
See how the -10 and 10 labels on the x-axis poke out to the left and right of the plot? And similar for the -1.0 and 1.0 labels on the y-axis. Can I automatically suppress plotting these but retain the ones that do not go outside the plot limits?
I think you could just format the axis ticks yourself and then prune the ones
that are hanging over. The recommended way to deal with setting up the axis is
to use the ticker API. So for example
from matplotlib.ticker import MaxNLocator
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
xvals=np.arange(-10,10,0.1)
yvals=[ np.sin(x) for x in xvals ]
ax.plot( xvals, yvals )
ax.xaxis.set_major_locator(MaxNLocator(prune='both'))
plt.show()
Here we are creating a figure and axes, plotting the data, and then setting the xaxis
major ticks. The formatter MaxNLocator is given the
argument prune='both' which is described in the docs here.
This is not exactly what you were asking for, but maybe it will solve your problem.

Copying axis limits from one subplot ('equal' aspect) to another

In a figure with 2x2 subplots, I need both the subplots on the right to share the x-axis, but the ones on the left not to share their axis. In addition, I need the subplot that is determining the x-axis limits to have 'equal' aspect ratio. I tried this:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(12, 9))
# Subplot [0,1]
ax[0,1].axis('equal')
ax[0,1].plot(...)
[xmin01, xmax01, ymin01, ymax01] = self.ax[0,1].axis()
# Subplot [1,1]
ax[1,1].plot(...)
ax[1,1].set_xlim(left=xmin01, right=xmax01)
This is not working: the limits of the x-axis returned by axis() are near the data limits and are not the real limits shown in the graphed subplot. Changing the position of ax[0,1].axis('equal') after the plot command has no effect. Any idea?
Looking into the pyplot source code I discovered that axis('equal') is calling the method set_aspect(). This latter method is modifying the variable self._aspect but it is not further updating anything related! Then, I looked for and found the method that is really updating the aspect ratio: it is named apply_aspect(). So, it doesn't seem very elegant, but at least my problem is solved as shown:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(12, 9))
# Subplot [0,1]
ax[0,1].axis('equal')
ax[0,1].plot(...)
ax[0,1].apply_aspect()
[xmin01, xmax01, ymin01, ymax01] = self.ax[0,1].axis()
# Subplot [1,1]
ax[1,1].plot(...)
ax[1,1].set_xlim(left=xmin01, right=xmax01)

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)))