2017-10-17 5 views
0

je peux créer un simple diagramme en colonnes dans un matplotlib selon le dictionnaire « simple »:Dessiner un terrain dans lequel les données de texte de l'axe Y (non numériques), et les données numériques de l'axe X

import matplotlib.pyplot as plt 
D = {u'Label1':26, u'Label2': 17, u'Label3':30} 
plt.bar(range(len(D)), D.values(), align='center') 
plt.xticks(range(len(D)), D.keys()) 
plt.show() 

enter image description here Mais, comment puis-je créer ligne courbe sur le texte et les données numériques de ce Dictionarie, je ne sais pas?

Т_OLD = {'10': 'need1', '11': 'need2', '12': 'need1', '13': 'need2', '14': 'need1'} 

Comme l'image ci-dessous enter image description here

Répondre

2

Utilisez des valeurs numériques pour votre axe y tiques, puis les associer à des chaînes souhaitées avec plt.yticks():

import matplotlib.pyplot as plt 
import pandas as pd 

# example data 
times = pd.date_range(start='2017-10-17 00:00', end='2017-10-17 5:00', freq='H') 
data = np.random.choice([0,1], size=len(times)) 
data_labels = ['need1','need2'] 

fig, ax = plt.subplots() 
ax.plot(times, data, marker='o', linestyle="None") 
plt.yticks(data, data_labels) 
plt.xlabel("time") 

enter image description here

Remarque : Ce n'est généralement pas une bonne idée d'utiliser un graphique linéaire pour représenter les changements catégoriques dans le temps (par ex. om need1 à need2). Faire cela donne l'impression visuelle d'un continuum entre les points de temps, qui peut ne pas être précis. Ici, j'ai changé le style de traçage en points au lieu de lignes. Si, pour une raison quelconque, vous avez besoin des lignes, supprimez simplement linestyle="None" de l'appel au plt.plot().

MISE À JOUR
(par commentaires)

Pour faire ce travail avec une catégorie ordonnée ensemble de longueur arbitraire, utilisez ax.set_yticks() et ax.set_yticklabels() à la carte à l'axe y.

Par exemple, étant donné un ensemble de valeurs de l'axe y potentiels labels, laissez N la taille d'un sous-ensemble de labels (ici, nous allons mettre à 4, mais il pourrait être de toute taille).

Dessinez ensuite un échantillon aléatoire data de valeurs y et tracer en fonction du temps, en marquant les graduations de l'axe des y en fonction de l'ensemble complet labels. Notez que nous utilisons encore set_yticks() d'abord avec des marqueurs numériques, puis remplaçons avec nos étiquettes de catégorie avec set_yticklabels().

labels = np.array(['A','B','C','D','E','F','G']) 
N = 4 

# example data 
times = pd.date_range(start='2017-10-17 00:00', end='2017-10-17 5:00', freq='H') 
data = np.random.choice(np.arange(len(labels)), size=len(times)) 

fig, ax = plt.subplots(figsize=(15,10)) 
ax.plot(times, data, marker='o', linestyle="None") 
ax.set_yticks(np.arange(len(labels))) 
ax.set_yticklabels(labels) 
plt.xlabel("time") 
+0

Je veux vous demander une chose. Comment écrire du code pour un dictionnaire de n'importe quelle longueur. Si le dictionnaire est de longueur arbitraire et nous ne voulons pas spécifier explicitement les valeurs (data_labels = ['need1', 'need2']). –

+0

Bien sûr, voir ma réponse mise à jour. –

2

Cela donne le choix exact parcelle:

import matplotlib.pyplot as plt 
from collections import OrderedDict 

T_OLD = {'10' : 'need1', '11':'need2', '12':'need1', '13':'need2','14':'need1'} 
T_SRT = OrderedDict(sorted(T_OLD.items(), key=lambda t: t[0])) 

plt.plot(map(int, T_SRT.keys()), map(lambda x: int(x[-1]), T_SRT.values()),'r') 

plt.ylim([0.9,2.1]) 
ax = plt.gca() 
ax.set_yticks([1,2]) 
ax.set_yticklabels(['need1', 'need2']) 

plt.title('T_OLD') 
plt.xlabel('time') 
plt.ylabel('need') 

plt.show() 

Pour Python 3.X les lignes complotant doit convertir explicitement la sortie map() aux listes:

plt.plot(list(map(int, T_SRT.keys())), list(map(lambda x: int(x[-1]), T_SRT.values())),'r') 

comme en Python 3 .X map() renvoie un itérateur par opposition à une liste dans Python 2.7.

L'intrigue utilise les clés du dictionnaire converties en ints et les derniers éléments de need1 ou need2, également convertis en ints. Cela repose sur la structure particulière de vos données, si les valeurs où need1 et need3 il aurait besoin d'un couple plus d'opérations.

Après le traçage et la modification des limites d'axes, le programme modifie simplement les étiquettes de graduation aux positions y 1 et 2. Il a ensuite ajoute aussi le titre et les x et les étiquettes d'axe y.

La partie importante est que le dictionnaire/données d'entrée doit être trié. Une façon de le faire est d'utiliser OrderedDict. Ici T_SRT est un OrderedDict objet trié par clés dans T_OLD.

La sortie est la suivante:

enter image description here

Ceci est un cas plus général pour plusieurs valeurs/étiquettes dans T_OLD. Il suppose que l'étiquette est toujours 'needX'X est un nombre quelconque. Cela peut facilement être fait pour un cas général d'une chaîne qui précède le nombre mais il faudrait plus de traitement,

import matplotlib.pyplot as plt 
from collections import OrderedDict 
import re 

T_OLD = {'10' : 'need1', '11':'need8', '12':'need11', '13':'need1','14':'need3'} 
T_SRT = OrderedDict(sorted(T_OLD.items(), key=lambda t: t[0])) 

x_val = list(map(int, T_SRT.keys())) 
y_val = list(map(lambda x: int(re.findall(r'\d+', x)[-1]), T_SRT.values())) 

plt.plot(x_val, y_val,'r') 

plt.ylim([0.9*min(y_val),1.1*max(y_val)]) 
ax = plt.gca() 
y_axis = list(set(y_val)) 
ax.set_yticks(y_axis) 
ax.set_yticklabels(['need' + str(i) for i in y_axis]) 

plt.title('T_OLD') 
plt.xlabel('time') 
plt.ylabel('need') 

plt.show() 

Cette solution trouve le numéro à la fin de l'étiquette avec re.findall pour accueillir la possibilité de multi numéros de chiffres. La solution précédente a juste pris le dernier composant de la chaîne parce que les nombres étaient à un seul chiffre. Il suppose toujours que le numéro de la position de tracé est le dernier numéro de la chaîne, d'où le [-1]. Encore une fois pour la sortie de la carte Python 3.X est explicitement converti en liste, pas nécessaire dans Python 2.7.

Les étiquettes sont maintenant générées en sélectionnant d'abord des valeurs y uniques en utilisant set, puis en renommant leurs étiquettes par concaténation des chaînes 'need' avec son entier correspondant.

Les limites de l'axe des ordonnées sont fixées à 0,9 de la valeur minimale et à 1,1 de la valeur maximale. Le reste du format est comme avant.

Le résultat de ce cas de test est:

enter image description here

+0

Merci pour votre aide, mais en Python 3 soulève l'erreur TypeError: l'objet 'zip' n'est pas un sous-script. Pouvez-vous me dire comment réparer ce code? –

+0

Ajout de la ligne dont vous avez besoin dans Python 3, juste pour la future référence. – atru

+0

Je veux vous demander encore une chose. Comment écrire du code pour un dictionnaire de n'importe quelle longueur. Si le dictionnaire est de longueur arbitraire et que nous ne voulons pas spécifier explicitement les valeurs (ax.set_yticklabels (['need1', 'need2']), ....])). –

3

Vous pouvez utiliser numpy pour convertir le dictionnaire à un tableau avec deux colonnes, qui peuvent être représentées graphiquement.

import matplotlib.pyplot as plt 
import numpy as np 

T_OLD = {'10' : 'need1', '11':'need2', '12':'need1', '13':'need2','14':'need1'} 
x = list(zip(*T_OLD.items())) 
# sort array, since dictionary is unsorted 
x = np.array(x)[:,np.argsort(x[0])].T 
# let second column be "True" if "need2", else be "False 
x[:,1] = (x[:,1] == "need2").astype(int) 

# plot the two columns of the array 
plt.plot(x[:,0], x[:,1]) 
#set the labels accordinly 
plt.gca().set_yticks([0,1]) 
plt.gca().set_yticklabels(['need1', 'need2']) 

plt.show() 

enter image description here

Seraient une version, qui est indépendante sur le contenu réel du dictionnaire; seule hypothèse est que les clés peuvent être converties en flotteurs.

import matplotlib.pyplot as plt 
import numpy as np 

T_OLD = {'10': 'run', '11': 'tea', '12': 'mathematics', '13': 'run', '14' :'chemistry'} 
x = np.array(list(zip(*T_OLD.items()))) 
u, ind = np.unique(x[1,:], return_inverse=True) 
x[1,:] = ind 
x = x.astype(float)[:,np.argsort(x[0])].T 

# plot the two columns of the array 
plt.plot(x[:,0], x[:,1]) 
#set the labels accordinly 
plt.gca().set_yticks(range(len(u))) 
plt.gca().set_yticklabels(u) 

plt.show() 

enter image description here

+0

Merci pour votre aide, mais en Python 3 soulève l'erreur TypeError: l'objet 'zip' n'est pas un sous-script. Pouvez-vous me dire comment réparer ce code? –

+0

Qu'en est-il de 'x = list (zip (* T_OLD.items()))'? – ImportanceOfBeingErnest

+0

J'ai essayé, mais Python 3 soulève l'erreur ValueError: impossible de convertir la chaîne en float: 'False' ( –