【问题标题】:Matplotlib bar graph x axis won't plot string valuesMatplotlib 条形图 x 轴不会绘制字符串值
【发布时间】:2012-02-24 11:14:03
【问题描述】:

我叫大卫,我在佛罗里达州的救护车服务部门工作。

我正在使用 Python 2.7 和 matplotlib。我正在尝试访问我的救护车呼叫数据库并计算每个工作日发生的呼叫数量。

然后,我将使用 matplotlib 创建此信息的条形图,为医护人员提供他们每天忙碌程度的直观图形。

这是运行良好的代码:

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

上面显示的代码运行良好。它返回一个漂亮的图表,我很高兴。我只想做一个改变。

X 轴不是显示星期几的名称,例如“星期日”,而是显示整数。换句话说,星期日是 1,星期一是 2,等等。

我的解决方法是重写我的 sql 查询以使用 DATENAME() 而不是 DATEPART()。 下面显示的是我的 sql 代码,用于返回星期的名称(而不是整数)。

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)

我的 python 代码中的其他所有内容都保持不变。但是这不起作用,我无法理解错误消息。

以下是错误消息:

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

我想不通。

总之,当我输出我的数据时,x 轴为整数,表示星期几,y 轴显示救护车事故的数量,Matplotlib 将生成一个漂亮的图表。但是当我的数据输出是 x 轴是一个字符串(星期日、星期一等)。那么 Matplotlib 将无法工作。

我在 Google 上做了几个小时的研究并阅读了 matplotlib 文档。 请帮我解决一下这个。我希望使用 Matplotlib 作为我的报告引擎。

【问题讨论】:

    标签: python matplotlib bar-chart


    【解决方案1】:

    您的问题与 SQL 查询无关,它只是一种结束的手段。您真正要问的是如何更改 pylab 条形图上的文本标签。 bar chart 的文档对于自定义很有用,但这里只是 change the labels 是一个最小的工作示例 (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()
    

    【讨论】:

    • 有没有人觉得条形图默认不接受字符串标签很奇怪?
    • @欧文。在这一点上,matplotlib 太奇怪了,我怀疑没有人真正理解为什么会发生任何事情。
    • @欧文。幸运的是 seaborn(虽然是基于 matplotlib 构建的)似乎没有这个问题(stackoverflow.com/q/32528154/4900327)。
    • 这正是我正在寻找的场景。我有一个长度为 20 个字符串的数组,以及其他长度相同的整数数组,并且正在考虑将这些与 y 轴上的 int 数组和 x 轴上的字符串数组建立关系。谢谢。
    【解决方案2】:

    不要仅仅为了改变插图而更改您的 SQL 代码。相反,对您的 Python 代码做一点补充。

    我相信你可以做类似this answer 的事情。将刻度标签设置为星期几。

    这可能就像添加以下行一样简单:

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

    Documentation: pyplot.xticks

    编辑:使用虚构表 IncidentTypes 来响应评论的示例,该表将整数键映射到事件类型的名称。

    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)
    

    【讨论】:

    • 这看起来可能是一个很好的答案。我现在要尝试一下。不幸的是,我需要创建的下一个条形图是救护车响应的事件类型的数量。大约有 60 种不同类型的事件。我无法为 x 轴硬编码 60 种不同类型的值。它太容易出错了。
    • 上一篇文章的继续。 SPSS 和 SAS 使用标称值轻松创建条形图。我很难相信这对 Matplotlib 来说是如此困难。一定有一些我想念的简单的东西!但它是什么?
    • 重新评论:您可以添加一个 SQL 表,将整数映射到天或整数映射到事件类型。示例:create table IncidentTypes (pk int primary key auto_increment, Name varchar(20))。然后加入表格。这是灵活和模块化的。您可以通过键 (int) 或名称(在 Python 中)来引用事件类型。
    • 第二条评论:添加上面的行并不太麻烦。如果你看到this example in the docs,他们会做同样的事情。要获取标签(第二个参数),您可以在 Python 中从我之前评论中建议的 SQL 表中读取它们。
    • 非常感谢史蒂夫。只要 StackOverflow 允许我这样做,我就会发布最终的有效代码。我得到了这个工作,它创建了一个很好的演示图形。将发布最终生成的代码供其他人查看。
    【解决方案3】:

    解决问题的最终完整答案: 非常感谢史蒂夫。你帮了大忙。我在大学里学的是地理,不是编程,所以这对我来说相当困难。 这是对我有用的最终代码。

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

    我不太理解“results=cursor.fetchall()”和以下四行涉及创建数组的代码之间的行。我很高兴你这样做,因为我看着它,它仍然没有沉入水中。 非常感谢您。这有很大帮助。 大卫

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-06
      • 2021-03-18
      相关资源
      最近更新 更多