How to draw axis in the middle of the figure?

PythonMatplotlibDrawing

Python Problem Overview


I want to draw a figure in matplotib where the axis are displayed within the plot itself not on the side

I have tried the following code from here:

import math
import numpy as np
import matplotlib.pyplot as plt

def sigmoid(x):
    a = []
    for item in x:
        a.append(1/(1+math.exp(-item)))
    return a

x = np.arange(-10., 10., 0.2)
sig = sigmoid(x)

plt.plot(x,sig)
plt.show()

The above code displays the figure like this:

What I would like to draw is something as follows (image from Wikipedia)

This question describes a similar problem, but it draws a reference line in the middle but no axis.

Python Solutions


Solution 1 - Python

One way to do it is using spines:

import math
import numpy as np
import matplotlib.pyplot as plt

def sigmoid(x):
    a = []
    for item in x:
        a.append(1/(1+math.exp(-item)))
    return a

    
x = np.arange(-10., 10., 0.2)
sig = sigmoid(x)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

# Move left y-axis and bottim x-axis to centre, passing through (0,0)
ax.spines['left'].set_position('center')
ax.spines['bottom'].set_position('center')

# Eliminate upper and right axes
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

# Show ticks in the left and lower axes only
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')

plt.plot(x,sig)
plt.show()

shows: enter image description here

Solution 2 - Python

Basically, I want to comment on the accepted answer (but my rep doesn't allow that). The use of

ax.spines['bottom'].set_position('center')

draws the x-axes such that it intersect the y-axes in its center. In case of asymmetric ylim this means that x-axis passes NOT through y=0. Jblasco's answer has this drawback, the intersect is at y=0.5 (the center between ymin=0.0 and ymax=1.0) However, the reference plot of the original question has axes that intersect each other at 0.0 (which is somehow conventional or at least common). To achieve this behaviour,

ax.spines['bottom'].set_position('zero')

has to be used. See the following example, where 'zero' makes the axes intersect at 0.0 despite asymmetrically ranges in both x and y.

import numpy as np
import matplotlib.pyplot as plt

#data generation
x = np.arange(-10,20,0.2)
y = 1.0/(1.0+np.exp(-x)) # nunpy does the calculation elementwise for you


fig, [ax0, ax1] = plt.subplots(ncols=2, figsize=(8,4))

# Eliminate upper and right axes
ax0.spines['top'].set_visible(False)
ax0.spines['right'].set_visible(False)
# Show ticks on the left and lower axes only
ax0.xaxis.set_tick_params(bottom='on', top='off')
ax0.yaxis.set_tick_params(left='on', right='off')

# Move remaining spines to the center
ax0.set_title('center')
ax0.spines['bottom'].set_position('center') # spine for xaxis 
#    - will pass through the center of the y-values (which is 0)
ax0.spines['left'].set_position('center')  # spine for yaxis 
#    - will pass through the center of the x-values (which is 5)

ax0.plot(x,y)


# Eliminate upper and right axes
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
# Show ticks on the left and lower axes only (and let them protrude in both directions)
ax1.xaxis.set_tick_params(bottom='on', top='off', direction='inout')
ax1.yaxis.set_tick_params(left='on', right='off', direction='inout')

# Make spines pass through zero of the other axis
ax1.set_title('zero')
ax1.spines['bottom'].set_position('zero')
ax1.spines['left'].set_position('zero')

ax1.set_ylim(-0.4,1.0)

# No ticklabels at zero
ax1.set_xticks([-10,-5,5,10,15,20])
ax1.set_yticks([-0.4,-0.2,0.2,0.4,0.6,0.8,1.0])

ax1.plot(x,y)

plt.show() 

Final remark: If ax.spines['bottom'].set_position('zero') is used but zerois not within the plotted y-range, then the axes is shown at the boundary of the plot closer to zero.

Solution 3 - Python

The title of this question is how to draw the spine in the middle and the accepted answer does exactly that but what you guys draw is the sigmoid function and that one passes through y=0.5. So I think what you want is the spine centered according to your data. Matplotlib offers the spine position data for that (see documentation)

import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
sigmoid = np.vectorize(sigmoid) #vectorize function
values=np.linspace(-10, 10) #generate values between -10 and 10
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

#spine placement data centered
ax.spines['left'].set_position(('data', 0.0))
ax.spines['bottom'].set_position(('data', 0.0))
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

plt.plot(values, sigmoid(values))
plt.show()

Looks like this (Github):

enter image description here

Solution 4 - Python

You can simply add:

plt.axhline()
plt.axvline()

It's not fixed to the center, but it does the job very easily.

Working example:

import matplotlib.pyplot as plt
import numpy as np

def f(x):
    return np.sin(x) / (x/100)

delte = 100
Xs = np.arange(-delte, +delte +1, step=0.01)
Ys = np.array([f(x) for x in Xs])
plt.axhline(color='black', lw=0.5)
plt.axvline(color='black', lw=0.5)
plt.plot(Xs, Ys)
plt.show()

graph

Solution 5 - Python

If you use matplotlib >= 3.4.2, you can use Pandas syntax and do it in only one line:

plt.gca().spines[:].set_position('center')

You might find it cleaner to do it in 3 lines:

ax = plt.gca()
ax.spines[['top', 'right']].set_visible(False)
ax.spines[['left', 'bottom']].set_position('center')

See documentation here.
Check your matplotlib version with pip freeze and update it with pip install -U matplotlib.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShanView Question on Stackoverflow
Solution 1 - PythonJblascoView Answer on Stackoverflow
Solution 2 - PythonKarl der KaeferView Answer on Stackoverflow
Solution 3 - PythonCodingYourLifeView Answer on Stackoverflow
Solution 4 - Pythonroi3363View Answer on Stackoverflow
Solution 5 - PythonkotchwaneView Answer on Stackoverflow