【问题标题】:Python issue with matplotlib Pie Chart Function (erraneous labels)matplotlib 饼图函数的 Python 问题(错误的标签)
【发布时间】:2013-11-18 14:38:40
【问题描述】:

我在使用 matplotlib 设置饼图时遇到了一个奇怪的问题。出于某种原因,它似乎没有正确处理我的标签参数。

一点背景知识...我正在开发一种工具,它可以让我们创建表格来汇总我们的网络地图服务上的点击量。这基本上只是遍历所有日志文件并获取用户名、站点名称和日期\时间信息。我的第一部分工作得很好,它创建了一些很好的汇总表。但是,生成饼图显示谁使用每个站点最多(按用户名)将是一个不错的选择。我还可以创建饼图,其中每个图表都以站点命名。

不能正常工作的是标签。

我承认我根本没有使用 matplotlib,但是根据我在网上看到的代码示例,我的代码看起来很合理。只是为了仔细检查标签的数量是否与饼的切片数量相匹配,我为每个图表打印了结果,并且输入参数似乎是正确的,但也许我遗漏了什么?

我使用的输入表看起来不错,这是用于饼图的数据。这是我正在使用的特定功能:

#! /usr/local/bin/python

import arcpy, os
from pylab import *
import numpy as np

def CreatePieChart(table, out, case_field, name_field, data_field):

    # Make new folder
    _dir = os.path.join(out, 'Figures')
    if not os.path.exists(_dir):
        os.makedirs(_dir)

    # Grab unique values
    rows = arcpy.SearchCursor(table)
    cases = sorted(list(set(r.getValue(case_field) for r in rows)))
    del rows

    # vals dictionary
    vals_dict = {}

    # Make table views
    tv = arcpy.MakeTableView_management(table, 'temp_table')
    for case in cases:
        query = ''' {0} = '{1}' '''.format(arcpy.AddFieldDelimiters(tv, case_field), case)
        arcpy.SelectLayerByAttribute_management(tv, 'NEW_SELECTION', query)

        # Get total number for pie slice
        rows = arcpy.SearchCursor(tv)
        vals_dict[case] = [[r.getValue(name_field),r.getValue(data_field)] for r in rows]
        del rows

    # Populate Pie Chart
    for case,vals in vals_dict.iteritems():
        the_fig = figure(1, figsize=(8,8))
        axes([0.1, 0.1, 0.8, 0.8])
        fig = os.path.join(_dir, '{0}.png'.format(case.replace(' ','_')))
        ax = the_fig.add_subplot(111)
        label = [v[0] for v in vals]
        fracs = [v[1] for v in vals]
        print '%s %s %s' %(case,label,fracs)
        if len(label) == len(fracs):  # to make sure same number of labels as slices
            cmap = plt.cm.prism
            color = cmap(np.linspace(0., 1., len(fracs)))
            pie_wedges = pie(fracs,colors=color,labels=label,pctdistance=0.5, labeldistance=1.05)
            for wedge in pie_wedges[0]:
                wedge.set_edgecolor('white')
            ax.set_title(case)
            savefig(fig)
            print 'Created: %s' %fig
        del the_fig,label,pie_wedges,fracs
    return fig

if __name__ == '__main__':

    table = r'C:\TEMP\Usage_Summary.dbf'
    out = r'C:\TEMP'
    case = 'Site_ID'
    name = 'Username'
    data = 'Count'

    CreatePieChart(table, out, case, name, data)

这是打印到我的 Python 窗口的内容(切片数确实与标签的数量相匹配):

ElkRiver [u'elkriver', u'jasonco', u'jenibr', u'johnsh', u'nickme'] [731, 1, 2, 55, 58]
Created: C:\TEMP\Figures\ElkRiver.png
LongPrairie [u'brianya', u'chuckde', u'johnsh', u'longprairie', u'nickme', u'scottja'] [6, 7, 61, 129, 25, 3]
Created: C:\TEMP\Figures\LongPrairie.png
Madison [u'deanhe', u'johnsh', u'kathrynst', u'madison', u'scottja'] [7, 9, 1, 39, 1]
Created: C:\TEMP\Figures\Madison.png
NorthMankato [u' ', u'adamja', u'brianma', u'johnsh', u'johnvo', u'marksc', u'mattme', u'nickme', u'nmankato', u'scottja'] [20, 13, 65, 64, 8, 2, 4, 63, 64, 1]
Created: C:\TEMP\Figures\NorthMankato.png
Orono [u'arroned', u'davidma', u'dionsc', u'dougkl', u'gis_guest', u'jenibr', u'johnsh', u'kenad', u'kevinfi', u'kylele', u'marksc', u'natest', u'nickme', u'orono', u'samel', u'scottja', u'sethpe', u'sueda'] [2, 11, 1, 3, 5, 1, 40, 6, 1, 1, 5, 1, 37, 819, 8, 5, 2, 2]
Created: C:\TEMP\Figures\Orono.png
BellePlaine [u'billhe', u'billsc', u'bplaine', u'christopherga', u'craigla', u'dennisst', u'elkriver', u'empire', u'gis_guest', u'jasonfe', u'joedu', u'johnsh', u'joshst', u'lancefr', u'nickme', u'richardde', u'scottja', u'teresabu', u'travisje', u'wadena'] [3, 1, 331, 1, 1, 40, 1, 1, 12, 1, 27, 61, 4, 1, 47, 3, 12, 2, 2, 1]
Created: C:\TEMP\Figures\BellePlaine.png
Osseo [u'johnsh', u'karlan', u'kevinbi', u'marcusth', u'nickme', u'osseo', u'scottja'] [22, 2, 23, 11, 66, 54, 3]
Created: C:\TEMP\Figures\Osseo.png
EmpireTownship [u'empire', u'johnsh', u'lancefr', u'lanile', u'marksc', u'nickme', u'richardde', u'scottja', u'travisje'] [96, 10, 1, 14, 2, 224, 1, 1, 3]
Created: C:\TEMP\Figures\EmpireTownship.png
Courtland [u'courtland', u'empire', u'joedu', u'johnsh', u'nickme', u'scottja'] [24, 3, 3, 10, 27, 2]
Created: C:\TEMP\Figures\Courtland.png
LeSueur [u' ', u'johnsh', u'marksc', u'nickme'] [8, 6, 1, 98]
Created: C:\TEMP\Figures\LeSueur.png
Stratford [u'johnsh', u'neilgu', u'scottja', u'stratford'] [9, 3, 2, 47]
Created: C:\TEMP\Figures\Stratford.png
>>> 

幕后发生了一些奇怪的事情,因为图表中的标签比我传递给pie() 函数的标签要多得多。

我还没有发布图片的声誉,但我已经在 gis stack exchange 上发布了一张图片。 Here是可以查看图片的链接。图片来自创建的“Osseo”图表,您可以从我的打印声明中看到这些是切片和标签:

Osseo [u'johnsh', u'karlan', u'kevinbi', u'marcusth', u'nickme', u'osseo', u'scottja'] [22, 2, 23, 11, 66, 54, 3]

我不确定为什么要创建这么多额外的标签。我在这里遗漏了什么吗?

这是代码的干净版本,以便其他人可以测试:

#! /usr/local/bin/python

import os
from pylab import *
import numpy as np

_dir = os.path.join(os.getcwd(), 'Figures')
if not os.path.exists(_dir):
    os.makedirs(_dir)


vals_dict = {u'ElkRiver': [[u'elkriver', 731], [u'jasonco', 1], [u'jenibr', 2], [u'johnsh', 55], [u'nickme', 58]],
             u'LongPrairie': [[u'brianya', 6], [u'chuckde', 7], [u'johnsh', 61], [u'longprairie', 129], [u'nickme', 25],
            [u'scottja', 3]], u'Madison': [[u'deanhe', 7], [u'johnsh', 9], [u'kathrynst', 1], [u'madison', 39],
            [u'scottja', 1]], u'NorthMankato': [[u' ', 20], [u'adamja', 13],[u'brianma', 65], [u'johnsh', 64],
            [u'johnvo', 8], [u'marksc', 2], [u'mattme', 4], [u'nickme', 63], [u'nmankato', 64], [u'scottja', 1]],
            u'Orono': [[u'arroned', 2], [u'davidma', 11], [u'dionsc', 1], [u'dougkl', 3], [u'gis_guest', 5], [u'jenibr', 1],
            [u'johnsh', 40], [u'kenad', 6], [u'kevinfi', 1], [u'kylele', 1], [u'marksc', 5], [u'natest', 1], [u'nickme', 37],
            [u'orono', 819], [u'samel', 8], [u'scottja', 5], [u'sethpe', 2], [u'sueda', 2]], u'BellePlaine': [[u'billhe', 3],
            [u'billsc', 1], [u'bplaine', 331], [u'christopherga', 1], [u'craigla', 1], [u'dennisst', 40], [u'elkriver', 1],
            [u'empire', 1], [u'gis_guest', 12], [u'jasonfe', 1], [u'joedu', 27], [u'johnsh', 61], [u'joshst', 4], [u'lancefr', 1],
            [u'nickme', 47], [u'richardde', 3], [u'scottja', 12], [u'teresabu', 2], [u'travisje', 2], [u'wadena', 1]],
             u'Osseo': [[u'johnsh', 22], [u'karlan', 2], [u'kevinbi', 23], [u'marcusth', 11], [u'nickme', 66], [u'osseo', 54],
            [u'scottja', 3]], u'EmpireTownship': [[u'empire', 96], [u'johnsh', 10], [u'lancefr', 1], [u'lanile', 14], [u'marksc', 2],
            [u'nickme', 224], [u'richardde', 1], [u'scottja', 1], [u'travisje', 3]], u'Courtland': [[u'courtland', 24], [u'empire', 3],
            [u'joedu', 3], [u'johnsh', 10], [u'nickme', 27], [u'scottja', 2]], u'LeSueur': [[u' ', 8], [u'johnsh', 6], [u'marksc', 1],
            [u'nickme', 98]], u'Stratford': [[u'johnsh', 9], [u'neilgu', 3], [u'scottja', 2], [u'stratford', 47]]}


# Populate Pie Chart
for case,vals in vals_dict.iteritems():
    the_fig = figure(1, figsize=(8,8))
    axes([0.1, 0.1, 0.8, 0.8])
    fig = os.path.join(_dir, '{0}.png'.format(case.replace(' ','_')))
    ax = the_fig.add_subplot(111)
    label = [v[0] for v in vals]
    fracs = [v[1] for v in vals]
    print '%s %s %s' %(case,label,fracs)
    if len(label) == len(fracs):  # to make sure same number of labels as slices
        cmap = plt.cm.prism
        color = cmap(np.linspace(0., 1., len(fracs)))
        pie_wedges = pie(fracs,colors=color,labels=label,pctdistance=0.5, labeldistance=1.1)
        for wedge in pie_wedges[0]:
            wedge.set_edgecolor('white')
        ax.set_title(case)
        savefig(fig)
        print 'Created: %s' %fig
    del label,pie_wedges,fracs
    the_fig.clf()

【问题讨论】:

  • 如果您可以抽象出 arcpy 的内容以及依赖于您的机器的所有内容(即访问驱动器上的特定表文件),那么调试它会更容易。这将允许其他人运行您的示例,并可以进行调试。
  • 你能把这个简化为一个最小的例子吗?这里有太多不相关的代码,很难准确找出问题所在

标签: python charts matplotlib


【解决方案1】:

据我所知,无法运行您的示例,问题是您在循环中使用相同的数字来处理案例

for case,vals in vals_dict.iteritems():
    the_fig = figure(1, figsize=(8,8))

每次都会得到数字1,并且这个数字永远不会被清除。所以尝试创建一个新图形(调用figure(figsize=(8,8)) 而不是figure(1, figsize=(8,8))),或者在创建后立即清除图形(使用the_fig.clf())。让我知道这是否有帮助。

编辑:这是一个不显示轴的版本,并使用图例而不是标签,这样您就不会将标签挤在一起。我还在标签上加上了百分比,特别是因为使用你的配色方案,你有时会得到一些相同颜色的切片(我试图解决这个问题,但没有任何运气)。 Matplotlib 实际上在将小切片尽可能远离彼此方面做得相当不错,问题出在您的某些图表中,您的小切片太多,因此不可能将它们全部分开。这就是我改用图例的原因。

for case,vals in vals_dict.iteritems():
    the_fig = figure(figsize=(8,8))
    axes([0.1, 0.1, 0.8, 0.8])
    fig = os.path.join(_dir, '{0}.png'.format(case.replace(' ','_')))
    label = [v[0] for v in vals]
    fracs = [v[1] for v in vals]
    print '%s %s %s' %(case,label,fracs)
    if len(label) == len(fracs):  # to make sure same number of labels as slices
        cmap = plt.cm.prism
        color = cmap(np.linspace(0., 1., len(fracs)))
        pie_wedges = pie(fracs,colors=color,pctdistance=0.5, labeldistance=1.1)
        for wedge in pie_wedges[0]:
            wedge.set_edgecolor('white')
        legend(map(lambda x, f: '%s (%0.0f%%)' % (x, f), label, fracs), loc=4)
        title(case)
        savefig(fig)
        print 'Created: %s' %fig

【讨论】:

  • 谢谢你!我的很多问题是我并没有真正花时间查看文档(只是查看了在线示例代码)。清除数字就可以了。如果我可以再选一次你的大脑,你会不会碰巧知道如何在不添加子图的情况下标记每个图形?我不想在侧面显示轴和边界。
  • 另外,我添加了一个干净的版本,以便任何人都可以测试。有没有办法格式化饼图,这样所有的小切片就不会彼此相邻?在某些情况下,用户只访问了一个站点一两次,因此有很多小片段。感谢您迄今为止的帮助!同时,我将尝试查看文档,看看我是否可以自己解决。
  • @hunse。你真棒!!!!!太感谢了!我只是在看传说中的东西,并试图弄清楚如何让它发挥作用,但你打败了我(而且做得比我能做的要好得多)。我试图投票给你的答案以增加加分,但我的声誉太低了:(再次感谢你的帮助,结果很漂亮!
猜你喜欢
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多