2012-02-01 18 views
27

Il mio nome è David e io lavoro per un servizio di ambulanza in Florida.Matplotlib grafico a barre asse x non tracciare valori stringa

Sto usando Python 2.7 e matplotlib. Sto tentando di raggiungere il mio database di chiamate ambulanze e di contare il numero di chiamate che si verificano in ogni giorno della settimana.

Utilizzerò quindi matplotlib per creare un grafico a barre di queste informazioni per fornire ai paramedici un grafico visivo di quanto sono occupati ogni giorno.

Ecco il codice che funziona molto bene:

import pyodbc 
import matplotlib.pyplot as plt 
MySQLQuery = """ 
SELECT 
DATEPART(WEEKDAY, IIU_tDispatch)AS [DayOfWeekOfCall] 
, COUNT(DATEPART(WeekDay, IIU_tDispatch)) AS [DispatchesOnThisWeekday] 
FROM AmbulanceIncidents 
GROUP BY DATEPART(WEEKDAY, IIU_tDispatch) 
ORDER BY DATEPART(WEEKDAY, IIU_tDispatch) 
""" 
cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=MyServer;DATABASE=MyDatabase;UID=MyUserID;PWD=MyPassword') 
cursor = cnxn.cursor() 
GraphCursor = cnxn.cursor() 
cursor.execute(MySQLQuery) 

#generate a graph to display the data 
data = GraphCursor.fetchall() 
DayOfWeekOfCall, DispatchesOnThisWeekday = zip(*data) 
plt.bar(DayOfWeekOfCall, DispatchesOnThisWeekday) 
plt.grid() 
plt.title('Dispatches by Day of Week') 
plt.xlabel('Day of Week') 
plt.ylabel('Number of Dispatches') 
plt.show() 

il codice mostrato sopra funziona molto bene. Restituisce un grafico piacevole e sono felice. Voglio solo fare un cambiamento.

Invece dell'asse X che mostra i nomi dei giorni della settimana, come "Domenica", mostra il numero intero. In altre parole, domenica è 1, lunedì è 2, ecc.

La mia correzione per questo è che riscrivo la mia query sql per utilizzare DATENAME() anziché DATEPART(). Di seguito è riportato il mio codice SQL per restituire il nome della settimana (anziché un numero intero).

SELECT 
DATENAME(WEEKDAY, IIU_tDispatch)AS [DayOfWeekOfCall] 
, COUNT(DATENAME(WeekDay, IIU_tDispatch)) AS [DispatchesOnThisWeekday] 
FROM AmbulanceIncidents 
GROUP BY DATENAME(WEEKDAY, IIU_tDispatch) 
ORDER BY DATENAME(WEEKDAY, IIU_tDispatch) 

Tutto il resto nel mio codice Python rimane lo stesso. Tuttavia questo non funzionerà e non riesco a capire i messaggi di errore.

Qui ci sono i messaggi di errore:

Traceback (most recent call last): 
    File "C:\Documents and Settings\kulpandm\workspace\FiscalYearEndReport\CallVolumeByDayOfWeek.py", line 59, in 

<module> 
    plt.bar(DayOfWeekOfCall, DispatchesOnThisWeekday) 
    File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 2080, in bar 
    ret = ax.bar(left, height, width, bottom, **kwargs) 
    File "C:\Python27\lib\site-packages\matplotlib\axes.py", line 4740, in bar 
    self.add_patch(r) 
    File "C:\Python27\lib\site-packages\matplotlib\axes.py", line 1471, in add_patch 
    self._update_patch_limits(p) 
    File "C:\Python27\lib\site-packages\matplotlib\axes.py", line 1489, in _update_patch_limits 
    xys = patch.get_patch_transform().transform(vertices) 
    File "C:\Python27\lib\site-packages\matplotlib\patches.py", line 547, in get_patch_transform 
    self._update_patch_transform() 
    File "C:\Python27\lib\site-packages\matplotlib\patches.py", line 543, in _update_patch_transform 
    bbox = transforms.Bbox.from_bounds(x, y, width, height) 
    File "C:\Python27\lib\site-packages\matplotlib\transforms.py", line 745, in from_bounds 
    return Bbox.from_extents(x0, y0, x0 + width, y0 + height) 
TypeError: coercing to Unicode: need string or buffer, float found 

Non riesco a capire questo fuori.

In sintesi, quando ho uscita i miei dati con l'asse x come numeri interi che rappresentano i giorni della settimana e l'asse y che mostra un conteggio del numero di incidenti ambulanza, Matplotlib produrrà un bel grafico. Ma quando il mio output di dati è l'asse x è una stringa (domenica, lunedì, ecc.). quindi Matplotlib non funzionerà.

ho fatto diverse ore di ricerca su Google e la lettura della documentazione matplotlib. Per favore aiutatemi con questo. Spero di usare Matplotlib come motore dei miei rapporti.

risposta

6

Non modificare il codice SQL solo per modificare l'illustrazione. Invece, fai una piccola aggiunta al tuo codice Python.

Credo che si possa fare qualcosa come this answer. Imposta le etichette dei segni di graduazione come giorni della settimana.

Può essere semplice come aggiungendo la seguente riga:

plt.xticks((1, 2, ..., 7), ('Sunday', 'Monday', ..., 'Saturday')) 

Documentation: pyplot.xticks

EDIT: Esempio in risposta a commentare utilizzando una tabella fittizia IncidentTypes che associa chiavi intere di nomi dei tipi di incidente.

cursor.execute('select incident_type_id, count(*), incident_type 
    from Incidents join IncidentTypes using (incident_type_id) 
    group by incident_type_id') 
results = cursor.fetchall() 
tickpositions = [int(r[0]) for r in results] 
numincidents = [int(r[1]) for r in results] 
ticklabels = [r[2] for r in results] 

plt.bar(tickpositions, numincidents) 
plt.xticks(tickpositions, ticklabels) 
+0

Questo sembra che potrebbe essere una buona risposta. Ho intenzione di provarlo subito. Sfortunatamente, il prossimo grafico a barre che devo creare è il numero di tipi di incidenti che le ambulanze rispondono. Ci sono circa 60 diversi tipi di incidenti. Non riesco a codificare hard 60 diversi tipi di valori per l'asse x. È troppo incline all'errore. –

+0

continuazione dal post precedente. SPSS e SAS creano facilmente grafici a barre usando valori nominali. Ho difficoltà a credere che sia così difficile per Matplotlib. Deve esserci qualcosa di semplice che mi manca! Ma cos'è ? –

+0

Nuovo commento: è possibile aggiungere una tabella SQL che mappa gli interi in giorni o numeri interi in tipi di incidente. Esempio: 'create table IncidentTypes (pk int chiave primaria auto_increment, Name varchar (20))'. Quindi unisciti ai tavoli. Questo è flessibile e modulare. È possibile fare riferimento a un tipo di incidente tramite chiave (int) o nome (in Python). –

1

finale risposta completato che ha risolto il problema: Grazie mille Steve. Sei stato di grande aiuto. Ho studiato geografia all'università, non alla programmazione, quindi per me è abbastanza difficile. Ecco il codice finale che funziona per me.

import pyodbc 
    import matplotlib.pyplot as plt 
    MySQLQuery = """ 
    SELECT 
     DATEPART(WEEKDAY, IIU_tDispatch)AS [IntegerOfDayOfWeek] 
    , COUNT(DATENAME(WeekDay, IIU_tDispatch)) AS [DispatchesOnThisWeekday] 
    , DATENAME(WEEKDAY, IIU_tDispatch)AS [DayOfWeekOfCall] 
    FROM IIncidentUnitSummary 
    INNER JOIN PUnit ON IIU_kUnit = PUN_Unit_PK 
    WHERE PUN_UnitAgency = 'LC' 
    AND IIU_tDispatch BETWEEN 'October 1, 2010' AND 'October 1, 2011' 
    AND PUN_UnitID LIKE 'M__' 
    GROUP BY DATEPART(WEEKDAY, IIU_tDispatch), DATENAME(WEEKDAY, IIU_tDispatch) 
    ORDER BY DATEPART(WEEKDAY, IIU_tDispatch) 
    """ 
    cnxn = pyodbc.connect("a bunch of stuff I don't want to share") 
    cursor = cnxn.cursor() 
    GraphCursor = cnxn.cursor() 
    cursor.execute(MySQLQuery) 

    results = cursor.fetchall() 
    IntegerDayOfWeek, DispatchesOnThisWeekday, DayOfWeekOfCall = zip(*results) 
    tickpositions = [int(r[0]) for r in results] 
    numincidents = [int(r[1]) for r in results] 
    ticklabels = [r[2] for r in results] 
    plt.bar(tickpositions, numincidents) 
    plt.xticks(tickpositions, ticklabels) 
    #plt.bar(DayOfWeekOfCall, DispatchesOnThisWeekday) 
    plt.grid() 
    plt.title('Dispatches by Day of Week') 
    plt.xlabel('Day of Week') 
    plt.ylabel('Number of Dispatches') 
    plt.show() 

    cursor.close() 
    cnxn.close() 

non capisco le linee tra "risultati = cursor.fetchall()" e le seguenti quattro righe di codice che coinvolgono creazione di array. Sono contento che tu lo faccia, perché lo guardo e continua a non affondare. grazie mille. Questo aiuta molto. David

59

La tua domanda non ha nulla a che fare con una query SQL, è semplicemente un mezzo per terminare. Quello che stai veramente chiedendo è come cambiare le etichette di testo su un grafico a barre in pylab. La documentazione per la bar chart sono utili per la personalizzazione, ma semplicemente change the labels ecco un esempio minimo di lavoro (MWE):

import pylab as plt 

DayOfWeekOfCall = [1,2,3] 
DispatchesOnThisWeekday = [77, 32, 42] 

LABELS = ["Monday", "Tuesday", "Wednesday"] 

plt.bar(DayOfWeekOfCall, DispatchesOnThisWeekday, align='center') 
plt.xticks(DayOfWeekOfCall, LABELS) 
plt.show() 

enter image description here

+9

Qualcun altro trova strano che un grafico a barre non accetti le etichette stringa per impostazione predefinita? – Owen

+1

@Owen. A questo punto Matplotlib è così strano che sospetto che nessuno capisca davvero perché succede qualcosa. –

+0

@Owen. Fortunatamente Seaborn (anche se costruito su Matplotlib) non sembra avere questo problema (https://stackoverflow.com/q/32528154/4900327). –

Problemi correlati