如何在饼图中创建超链接

3
我想用matplotlib绘制一个饼图。
这个饼图将代表两个变量:男性和女性。
这很容易做到 :)
接下来我想做的事情,我甚至不确定是否可能使用matplotlib完成,我希望让这两个变量可点击,所以如果我点击男性,我会看到另一页关于男性的信息,同样的事情也适用于女性。
图像映射不是解决方案,因为这些变量将来可能会发生变化。
有人有什么想法吗?如果可以在matplotlib中实现或者有什么其他程序可以推荐。
谢谢!
2个回答

5

虽然它还没有达到可用的稳定状态,但请看一下matplotlib的html5画布后端。无论如何,它看起来很有趣,并且可能是未来完成这种事情(具有matplotlib图的交互式网页)的最佳方式。

与此同时,正如@Mark所建议的那样,动态生成饼图楔形区域的图像映射并不太难。

这里有一个粗略的示例,我相信您可以根据自己使用的任何Web框架进行适应。

import matplotlib.pyplot as plt

def main():
    # Make an example pie plot
    fig = plt.figure()
    ax = fig.add_subplot(111)

    labels = ['Beans', 'Squash', 'Corn']
    wedges, plt_labels = ax.pie([20, 40, 60], labels=labels)
    ax.axis('equal')

    make_image_map(fig, wedges, labels, 'temp.html')

def make_image_map(fig, wedges, labels, html_filename):
    """Makes an example static html page with a image map of a pie chart.."""
    #-- Save the figure as an image and get image size ------------------------
    # Be sure to explictly set the dpi when saving the figure
    im_filename = 'temp.png'
    fig.savefig(im_filename, dpi=fig.dpi)

    # Get figure size...
    _, _, fig_width, fig_height = fig.bbox.bounds

    #-- Get the coordinates of each wedge as a string of x1,y2,x2,y2... -------
    coords = []
    for wedge in wedges:
        xy = wedge.get_verts() 

        # Transform to pixel coords
        xy = fig.get_transform().transform(xy) 

        # Format into coord string and convert to <0,0> in top left...
        xy = ', '.join(['%0.2f,%0.2f' % (x, fig_height - y) for x, y in xy])
        coords.append(xy)

    #-- Build web page --------------------------------------------------------
    header = """
    <html>
    <body>
    <img src="{0}" alt="Pie Chart" usemap="#pie_map" width="{1}" height="{2}" />
    """.format(im_filename, fig_width, fig_height)

    # Make the image map
    map = '<map name="pie_map">\n'
    for label, xy in zip(labels, coords):
        href = 'http://images.google.com/images?q={0}'.format(label)
        area = '<area shape="poly" coords="{0}" href="{1}" alt="{2}" />'
        area = area.format(xy, href, label)
        map += '    ' + area + '\n'
    map += '</map>\n'

    footer = """
    </body>
    </html>"""

    # Write to a file...
    with file(html_filename, 'w') as outfile:
        outfile.write(header + map + footer)

if __name__ == '__main__':
    main()

编辑:我刚意识到你可能不是在指将图表嵌入网页...(我假设你是从你的问题中的“显示另一页”那一点上得出的结论。)如果你想要更像桌面应用程序,而不必去烦恼一个“完整”的 GUI 工具包,你可以像这样做:

import matplotlib.pyplot as plt

def main():
    # Make an example pie plot
    fig = plt.figure()
    ax = fig.add_subplot(111)

    labels = ['Beans', 'Squash', 'Corn']
    wedges, plt_labels = ax.pie([20, 40, 60], labels=labels)
    ax.axis('equal')

    make_picker(fig, wedges)
    plt.show()

def make_picker(fig, wedges):
    import webbrowser
    def on_pick(event):
        wedge = event.artist
        label = wedge.get_label()
        webbrowser.open('http://images.google.com/images?q={0}'.format(label))

    # Make wedges selectable
    for wedge in wedges:
        wedge.set_picker(True)

    fig.canvas.mpl_connect('pick_event', on_pick)

if __name__ == '__main__':
    main()

这将打开一个浏览器窗口,搜索以楔子标记的任何内容的谷歌图片...


谢谢Joe,非常详细并且提供了很多例子。非常好 :) 我正在尝试在Django和HTML中实现这个,但我不太理解你的HTML。通常我会将图片链接或保存位置放在那里。 - psoares
@Patricia - 在第一个示例中,这就是我所做的一切... 它只是将图像保存到磁盘中,插入一个<img src="filename.png" />,然后基于饼图中的楔形生成已保存图像的映像。 (Stackoverflow的语法突出显示在所有具有嵌套",'"""的字符串中都有点问题)关键是在“#-获取每个楔形的坐标...”下面的循环。 我只是抓取每个楔形的顶点,将它们转换为已保存图像的像素坐标,并生成包含这些坐标的字符串。希望这可以帮助! - Joe Kington
我认为我的错误可能出现在某个地方,因为当我将变量传递到模板时,它什么也没有做。 - psoares
@Patricia - 第一个例子应该创建两个文件... "temp.png",以及您在函数中传递的文件名(例如,在示例中为"temp.html")... - Joe Kington
希望我能给这个答案加10分。太棒了的例子...虽然动态生成饼图图像映射不是“太难”,但它仍然足够难,你的例子是一个巨大的时间节省者! - Gerrat
显示剩余8条评论

1

你可以使用图像地图或由JavaScript / jQuery控制的HTML元素叠加来实现这一点。

基本上,将您的图表数据与图表图像一起发送到页面,并使用JS根据数据规范创建具有链接的元素。

这比我以前做过的条形图更难,但应该可以正常工作。


如果数据总是相同的话,那就很容易了,可以使用图像映射来解决。但是数据可能会有所不同,因此必须自行计算。这应该使用js或jq吗? - psoares
是的,您可以使用JavaScript / jQuery创建和修改任何想象得到的元素。我会看看是否能稍后提供代码示例。 - Mark Snidovich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接