2012-02-01 19 views
27

Mi nombre es David y trabajo para un servicio de ambulancia en Florida.Matplotlib gráfico de barras eje x no trazará valores de cadena

Estoy usando Python 2.7 y matplotlib. Estoy intentando acceder a mi base de datos de llamadas de ambulancia y contar el número de llamadas que ocurren en cada día de la semana.

Usaré matplotlib para crear un gráfico de barras de esta información para dar a los paramédicos un gráfico visual de lo ocupados que están en cada día.

aquí es el código que funciona muy bien:

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

incluya la palabra clave funciona muy bien. Devuelve un bonito gráfico y estoy contento. Solo quiero hacer un cambio.

En lugar de que el eje X muestre los nombres de los días de la semana, como "Domingo", muestra el número entero. En otras palabras, domingo es 1, lunes es 2, etc.

Mi solución para esto es que reescribo mi consulta SQL para usar DATENAME() en lugar de DATEPART(). A continuación se muestra mi código SQL para devolver el nombre de la semana (en lugar de un número entero).

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) 

Todo lo demás en mi código python sigue siendo el mismo. Sin embargo, esto no funcionará y no puedo entender los mensajes de error.

Éstos son los mensajes de error:

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 

no puedo resolver esto.

En resumen, cuando imprimo mis datos con el eje x como enteros que representan los días de la semana y el eje y que muestra un recuento de la cantidad de incidentes de ambulancia, Matplotlib generará un buen gráfico. Pero cuando mi salida de datos es el eje x es una cadena (domingo, lunes, etc.). entonces Matplotlib no funcionará.

He realizado varias horas de investigación en Google y he leído la documentación de matplotlib. Por favor, ayúdenme con esto. Espero utilizar Matplotlib como mi motor de informes.

Respuesta

6

No cambie su código SQL solo para alterar la ilustración. En su lugar, haga una pequeña adición a su código Python.

Creo que puede hacer algo como this answer. Establezca las etiquetas de tic en los días de la semana.

Puede ser tan simple como añadir la línea siguiente:

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

Documentation: pyplot.xticks

EDIT: Ejemplo En respuesta al comentario usando una tabla de ficción IncidentTypes que mapea claves enteras a los nombres de tipos de incidentes.

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

Esto parece que podría ser una buena respuesta. Voy a probarlo en este momento. Desafortunadamente, el siguiente gráfico de barras que necesito crear es la cantidad de tipos de incidentes a los que responden las ambulancias. Hay alrededor de 60 tipos diferentes de incidentes. No puedo codificar 60 tipos de valores para el eje x. Es demasiado propenso al error. –

+0

continuación de la publicación anterior. SPSS y SAS crean fácilmente gráficos de barras utilizando valores nominales. Me cuesta creer que esto sea tan difícil para Matplotlib. ¡Tiene que haber algo fácil que me falta! Pero, qué es esto ? –

+0

Primer comentario: Se podría agregar una tabla SQL que asigna números enteros a días o enteros a tipos de incidentes. Ejemplo: 'create table IncidentTypes (pk int clave primaria auto_increment, Name varchar (20))'. Entonces solo únete a las tablas. Esto es flexible y modular. Puede hacer referencia a un tipo de incidente por clave (int) o nombre (en Python). –

1

final completado respuesta que resuelva el problema: Muchas gracias Steve. Tú has sido de gran ayuda. Estudié geografía en la universidad, no programación, así que esto es bastante difícil para mí. Aquí está el código final que funciona para mí.

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

yo no entiendo muy bien los límites entre "los resultados = cursor.fetchall()" y las siguientes cuatro líneas de código que implican la creación de matrices. Me alegro de que lo hagas, porque lo veo y todavía no funciona. muchas gracias. Esto ayuda mucho. David

59

Su pregunta no tiene nada que ver con una consulta SQL, es simplemente un medio para finalizar. Lo que realmente está preguntando es cómo cambiar las etiquetas de texto en un gráfico de barras en pylab. La documentación para el bar chart son útiles para la personalización, sino simplemente change the labels aquí es un ejemplo de trabajo mínima (EPM):

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

¿Alguien más encuentra extraño que un gráfico de barras no acepte etiquetas de cadena por defecto? – Owen

+1

@Owen. En este punto matplotlib es tan extraño que sospecho que nadie realmente entiende por qué sucede algo. –

+0

@Owen. Afortunadamente, nacido en el mar (aunque está basado en matplotlib) no parece tener este problema (https://stackoverflow.com/q/32528154/4900327). –

Cuestiones relacionadas