2017-03-17 99 views
1

我正在使用此Matplotlib User Interface example,并且当我运行基本示例时,它的工作原理与广告一样。当我开始适应我的需求时,事情就开始横向了。Matplotlib用户界面示例打破多个三个修补程序

  • 当我添加第三个补丁时,它仍然按照广告方式工作。
  • 当我添加第四个补丁时,其鼠标悬停似乎被映射到子图的X轴顶部而不是该补丁。
  • 当我添加第五个修补程序时,第四个修补程序仍然映射到子图的X轴顶部,我找不到第五个修补程序的鼠标悬停区域。

我无法弄清楚在修补程序> 3时会使脚本生气的原因。看看脚本,它似乎应该适用于任何数量的修补程序。 SVG在Safari,Firefox和Chrome中显示相同的行为。

任何指针将不胜感激。

[Python的2.7.10,Matplotlib 1.3.1]

#! /usr/bin/env python 
# -*- coding: utf-8 -*- 

from io import BytesIO 
import matplotlib.patches as mpatches 
import matplotlib.pyplot as plt 
import xml.etree.ElementTree as ET 

ET.register_namespace("", "http://www.w3.org/2000/svg") 

fig = plt.figure(figsize=(25,10)) 
fig, ax1 = plt.subplots() 

ax1.add_patch(mpatches.FancyBboxPatch((1980, 1), 1, 1, boxstyle=mpatches.BoxStyle("Round", pad=0.15))) 
ax1.annotate('One', xy=(1980, 1), xytext=(0, 0), textcoords='offset points', color='w', ha='center', fontsize=8, bbox=dict(boxstyle='round, pad=.5', fc=(.1, .1, .1, .92), ec=(1., 1., 1.), lw=1, zorder=1)) 

ax1.add_patch(mpatches.FancyBboxPatch((1990, 2), 1, 1, boxstyle=mpatches.BoxStyle("Round", pad=0.15))) 
ax1.annotate('Two', xy=(1990, 2), xytext=(0, 0), textcoords='offset points', color='w', ha='center', fontsize=8, bbox=dict(boxstyle='round, pad=.5', fc=(.1, .1, .1, .92), ec=(1., 1., 1.), lw=1, zorder=1)) 

ax1.add_patch(mpatches.FancyBboxPatch((2000, 3), 1, 1, boxstyle=mpatches.BoxStyle("Round", pad=0.15))) 
ax1.annotate('Three', xy=(2000, 3), xytext=(0, 0), textcoords='offset points', color='w', ha='center', fontsize=8, bbox=dict(boxstyle='round, pad=.5', fc=(.1, .1, .1, .92), ec=(1., 1., 1.), lw=1, zorder=1)) 

ax1.add_patch(mpatches.FancyBboxPatch((2010, 4), 1, 1, boxstyle=mpatches.BoxStyle("Round", pad=0.15))) 
ax1.annotate('Four', xy=(2010, 4), xytext=(0, 0), textcoords='offset points', color='w', ha='center', fontsize=8, bbox=dict(boxstyle='round, pad=.5', fc=(.1, .1, .1, .92), ec=(1., 1., 1.), lw=1, zorder=1)) 

# Save the figure in a fake file object 
ax1.set_xlim(1970, 2017) 
ax1.set_ylim(0, 8) 

# Set id for the patches 
for i, t in enumerate(ax1.patches): 
    t.set_gid('patch_%d' % i) 

# Set id for the annotations 
for i, t in enumerate(ax1.texts): 
    t.set_gid('tooltip_%d' % i) 

f = BytesIO() 
plt.savefig(f, format="svg") 

# --- Add interactivity --- 

# Create XML tree from the SVG file. 
tree, xmlid = ET.XMLID(f.getvalue()) 
tree.set('onload', 'init(evt)') 

# Hide the tooltips 
for i, t in enumerate(ax1.texts): 
    el = xmlid['tooltip_%d' % i] 
    el.set('visibility', 'hidden') 

# Assign onmouseover and onmouseout callbacks to patches. 
for i, t in enumerate(ax1.patches): 
    el = xmlid['patch_%d' % i] 
    el.set('onmouseover', "ShowTooltip(this)") 
    el.set('onmouseout', "HideTooltip(this)") 

# This is the script defining the ShowTooltip and HideTooltip functions. 
script = """ 
    <script type="text/ecmascript"> 
    <![CDATA[ 

    function init(evt) { 
     if (window.svgDocument == null) { 
      svgDocument = evt.target.ownerDocument; 
      } 
     } 

    function ShowTooltip(obj) { 
     var cur = obj.id.slice(-1); 

     var tip = svgDocument.getElementById('tooltip_' + cur); 
     tip.setAttribute('visibility',"visible") 
     } 

    function HideTooltip(obj) { 
     var cur = obj.id.slice(-1); 
     var tip = svgDocument.getElementById('tooltip_' + cur); 
     tip.setAttribute('visibility',"hidden") 
     } 

    ]]> 
    </script> 
    """ 

# Insert the script at the top of the file and save it. 
tree.insert(0, ET.XML(script)) 
ET.ElementTree(tree).write('svg_tooltip_1.svg') 

[ETA:输出路径]

探索输出路径,我得到这个,这显示了一些明显错误与第四路径。

路径1:

<path clip-path="url(#p7ff5b81e1d)" d=" M161.28 352.08 L170.208 352.08 Q171.547 352.08 171.547 345.6 L171.547 302.4 Q171.547 295.92 170.208 295.92 L161.28 295.92 Q159.941 295.92 159.941 302.4 L159.941 345.6 Q159.941 352.08 161.28 352.08 z " style="fill:#0000ff;stroke:#000000;"/> 


</g> 

路径2:

<path clip-path="url(#p7ff5b81e1d)" d=" M250.56 308.88 L259.488 308.88 Q260.827 308.88 260.827 302.4 L260.827 259.2 Q260.827 252.72 259.488 252.72 L250.56 252.72 Q249.221 252.72 249.221 259.2 L249.221 302.4 Q249.221 308.88 250.56 308.88 z " style="fill:#0000ff;stroke:#000000;"/> 


</g> 

路径3:

<path clip-path="url(#p7ff5b81e1d)" d=" M339.84 265.68 L348.768 265.68 Q350.107 265.68 350.107 259.2 L350.107 216 Q350.107 209.52 348.768 209.52 L339.84 209.52 Q338.501 209.52 338.501 216 L338.501 259.2 Q338.501 265.68 339.84 265.68 z " style="fill:#0000ff;stroke:#000000;"/> 


</g> 

霸日4:

<path d=" M72 43.2 L518.4 43.2" style="fill:none;stroke:#000000;"/> 


</g> 

High Quality Image of Behavior

+0

这是非常奇怪的,尤其是因为它只取决于补丁/文本的数量(例如,忽略第一个使其适用于第四个)。 – ImportanceOfBeingErnest

+0

我知道,对吧?我做了任何排列方式,无法弄清楚。 – DaveL17

回答

2

我们不得不得出结论,从matplotlib页svg_tooltip example是错误的。

的问题来自于哪个迭代中轴线的补丁并添加一个名为patch_id一个ID,他们行

for i, t in enumerate(ax.patches): 
    t.set_gid('patch_%d' % i) 

。但是,这些轴可能比我们在代码中添加的更多。例如。轴刺也是补丁。因此,在遍历所有补丁时,我们可能会有意将id为"patch_4"的轴设置为轴,而不是我们要设置的补丁。

为了克服这个问题,我们实际上需要将ID设置到应该有的补丁,例如,通过迭代仅添加补丁。

第二个问题在这里:ID patch_id也被保存时画布中的其他元素使用。所以我们应该以不同的方式进行调用mypatch_id

接下来的问题是设置可见性和回调时,我们也不应该遍历画布中的所有文本和补丁,而只是覆盖那些有我们自己设置的id的对象。

请参阅下面的完整工作示例。

from io import BytesIO 
import matplotlib.patches as mpatches 
import matplotlib.pyplot as plt 
import xml.etree.ElementTree as ET 

ET.register_namespace("", "http://www.w3.org/2000/svg") 

fig = plt.figure(figsize=(25,10)) 
fig, ax1 = plt.subplots() 


years = [1980,1990, 2000, 2010] 
labels = ["One", "Two", "Three", "Four"] 

for i, year in enumerate(years): 
    patch = mpatches.FancyBboxPatch((year, i+1), 1, 1, 
         boxstyle=mpatches.BoxStyle("Round", pad=0.15)) 
    annotate = ax1.annotate(labels[i], xy=(year, i+1), xytext=(0, 0), 
        textcoords='offset points', color='w', ha='center', 
        fontsize=8, bbox=dict(boxstyle='round, pad=.5', fc=(.1, .1, .1, .92), 
        ec=(1., 1., 1.), lw=1, zorder=1)) 

    ax1.add_patch(patch) 
    patch.set_gid('mypatch_{:03d}'.format(i)) 
    annotate.set_gid('mytooltip_{:03d}'.format(i)) 


# Save the figure in a fake file object 
ax1.set_xlim(1970, 2017) 
ax1.set_ylim(0, 8) 


f = BytesIO() 
plt.savefig(f, format="svg") 

# --- Add interactivity --- 

# Create XML tree from the SVG file. 
tree, xmlid = ET.XMLID(f.getvalue()) 
tree.set('onload', 'init(evt)') 


for i, y in enumerate(years): 
    # Hide the tooltips 
    tooltip = xmlid['mytooltip_{:03d}'.format(i)] 
    tooltip.set('visibility', 'hidden') 
    # Assign onmouseover and onmouseout callbacks to patches. 
    mypatch = xmlid['mypatch_{:03d}'.format(i)] 
    mypatch.set('onmouseover', "ShowTooltip(this)") 
    mypatch.set('onmouseout', "HideTooltip(this)") 

# This is the script defining the ShowTooltip and HideTooltip functions. 
script = """ 
    <script type="text/ecmascript"> 
    <![CDATA[ 

    function init(evt) { 
     if (window.svgDocument == null) { 
      svgDocument = evt.target.ownerDocument; 
      } 
     } 

    function ShowTooltip(obj) { 
     var cur = obj.id.split("_")[1]; 
     var tip = svgDocument.getElementById('mytooltip_' + cur); 
     tip.setAttribute('visibility',"visible") 
     } 

    function HideTooltip(obj) { 
     var cur = obj.id.split("_")[1]; 
     var tip = svgDocument.getElementById('mytooltip_' + cur); 
     tip.setAttribute('visibility',"hidden") 
     } 

    ]]> 
    </script> 
    """ 

# Insert the script at the top of the file and save it. 
tree.insert(0, ET.XML(script)) 
ET.ElementTree(tree).write('svg_tooltip_2.svg') 
+0

这太棒了。非常感谢您解决问题并提供完美解决方案。您的解决方案还解决了以后如何添加更多补丁的难题,而补丁无关于接口。优秀。 – DaveL17

+0

p.s.我在GitHub上提出了一个说明,强调了这个问题,您的解决方案和乞求信用就归功于您。 – DaveL17

+0

只需注意脚本在修补程序为10或更少时工作良好。当应用第11个补丁时,SVG将显示与第一个补丁相关的工具提示。我怀疑它是来自原始matplotlib示例脚本的'obj.id.slice(-1)'。 – DaveL17

相关问题