web-dev-qa-db-fra.com

Comment dessiner un axe au milieu de la figure?

Je veux dessiner une figure dans matplotib où les axes sont affichés dans l'intrigue elle-même et non sur le côté

J'ai essayé le code suivant d'ici :

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

Le code ci-dessus affiche la figure comme ceci:

Ce que je voudrais dessiner est quelque chose comme suit (Image de Wiki)

Vu cela question , il trace une ligne de référence au milieu mais pas d'axe.

18
Shan

Une façon de le faire est d'utiliser épines :

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

spectacles: enter image description here

22
Jblasco

Fondamentalement, je veux commenter la réponse acceptée (mais mon représentant ne le permet pas). L'utilisation de

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

dessine les axes x de telle sorte qu'il coupe les axes y en son centre. En cas de ylim asymétrique, cela signifie que l'axe des x ne passe PAS par y = 0. La réponse de Jblasco a cet inconvénient, l'intersection est à y = 0,5 (le centre entre ymin = 0,0 et ymax = 1,0) Cependant, le tracé de référence de la question d'origine a des axes qui se coupent à 0,0 (ce qui est en quelque sorte conventionnel ou au moins commun). Pour obtenir ce comportement,

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

doit être utilisé. Voir l'exemple suivant, où "zéro" fait que les axes se coupent à 0,0 malgré des plages asymétriques à la fois en x et en 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() 

Remarque finale: Si ax.spines['bottom'].set_position('zero') est utilisé mais que les zéros ne sont pas dans la plage y tracée, alors les axes sont affichés à la limite du tracé plus près de zéro.

15
Karl der Kaefer

Le titre de cette question est de savoir comment dessiner la colonne vertébrale au milieu et la réponse acceptée fait exactement cela, mais ce que vous dessinez, c'est la fonction sigmoïde et que l'on passe par y = 0,5. Je pense donc que ce que vous voulez, c'est la colonne vertébrale centrée en fonction de vos données . Matplotlib offre la position de la colonne vertébrale données pour cela ( voir 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()

Ressemble à ceci ( Github ):

enter image description here

12
CodingYourLife