使用Matplotlib创建SVG折线图的工具提示

3
我想为使用matplotlib创建的SVG线图创建工具提示(显示数据值)。这将使用户能够单击或悬停在线图中的每个标记上,显示该特定点的值。
为了能够实现这一点,我需要访问Line2D对象的标记元素,并向每个此类元素添加gid。
http://matplotlib.org/examples/user_interfaces/svg_histogram.html上,有一个如何针对直方图完成此操作的示例。
H = plt.hist([r,r1], label=labels)
containers = H[-1]
hist_patches = {}
for ic, c in enumerate(containers):
    hist_patches['hist_%d'%ic] = []
    for il, element in enumerate(c):
        element.set_gid('hist_%d_patch_%d'%(ic, il))
        hist_patches['hist_%d'%ic].append('hist_%d_patch_%d'%(ic,il))

然而,如果我尝试使用折线图来做这件事,我发现Line2D对象不可迭代——可能是因为它不像直方图条形图一样是补丁集合。
H = plt.plot([1,2,3,4],[1,4,9,16], 'ro')
containers = H[-1]
enumerate(containers)

这导致出现错误:"TypeError: 'Line2D'对象不可迭代"
问题是如何从Line2D访问单个标记
有一些使用matplotlib交互后端的方法可以实现此操作。但我需要为非交互SVG实现此操作。

尝试迭代您传递给plotxy向量(或者迭代zip(x,y))。那些是您想要添加gids的点,对吗? - cphlewis
我知道这可以在交互式的matplotlib图中完成。如何在SVG中实现?你能提供一个例子吗? - user3897208
https://matplotlib.org/stable/gallery/user_interfaces/svg_tooltip_sgskip.html - Justin
2个回答

0

我修改了OP的代码 链接代码片段

这对于我来说有效。但是,我还没有找到区分各个标记的方法。

import matplotlib.pyplot as plt
import numpy as np
import xml.etree.ElementTree as ET
from io import BytesIO

plt.rcParams['svg.fonttype'] = 'none'
_ , ax = plt.subplots(figsize=(14,8))

Rand_Values = []
Rand_Values.append(np.random.rand(20)) 
Rand_Values.append(np.random.rand(20)) 
x_axis = range(20)

for i in range(2):
    H = ax.plot(x_axis, Rand_Values[i] , label= "data set %i" % (i+1))  
    ThisContainer = H[-1]                                     
    ThisContainer.set_gid('hist_%i' % i )

plt.xlabel("x-axis label") 
plt.ylabel("random data") 
plt.title( "Interactive chart" )  

leg = ax.legend(loc='upper left', bbox_to_anchor=(0, 1), ncol=1, fancybox=True, shadow=True)

for i, t in enumerate(leg.get_texts()):
    t.set_gid('leg_text_%d' % i)

# Save SVG in a fake file object.
f = BytesIO()
plt.savefig(f, format="svg")

# Create XML tree from the SVG file.
ET.register_namespace("", "http://www.w3.org/2000/svg")
tree, xmlid = ET.XMLID(f.getvalue())

# --- Add interactivity ---
# Add attributes to the text objects.
for i, t in enumerate(leg.get_texts()):
    el = xmlid['leg_text_%d' % i]
    el.set('cursor', 'pointer')
    el.set('onclick', "toggle_hist(this)")

# Create script defining the function `toggle_hist`.
script = """
<script type="text/ecmascript">
<![CDATA[

function toggle(oid, attribute, values) {
    /* Toggle the style attribute of an object between two values.

    Parameters
    ----------
    oid : str
      Object identifier.
    attribute : str
      Name of style attribute.
    values : [on state, off state]
      The two values that are switched between.
    */
    var obj = document.getElementById(oid);
    var a = obj.style[attribute];

    a = (a == values[0] || a == "") ? values[1] : values[0];
    obj.style[attribute] = a;
    }

function toggle_hist(obj) {
    var num = obj.id.replace( /^\D+/g, '');
    toggle( 'leg_text_' + num, 'opacity', [1, 0.5]);
    toggle( 'hist_'+ num  , 'opacity', [1,0]);
    }
]]>
</script>
""" 

# Add a transition effect
css = tree.getchildren()[0][0]

css.text = css.text + "g {-webkit-transition:opacity 0.4s ease-out;" + \
    "-moz-transition:opacity 0.4s ease-out;}"


# Insert the script and save to file.
tree.insert(0, ET.XML(script))

ET.ElementTree(tree).write("svg_lineChart.svg")

-2
一个更好的解决方案可能是使用Charts库。它可以让你使用优秀的Highcharts JavaScript库来制作美丽和交互式的图表。Highcharts使用HTML svg标签。
默认情况下,所有图表都将具有交互式工具提示!
免责声明:我是该库的开发人员。

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