Создание всплывающей подсказки для линейной диаграммы svg с использованием matplotlib

Я хочу создать всплывающие подсказки (показывающие значения данных) для линейных диаграмм SVG, созданных с помощью matplotlib. Это позволит пользователю щелкнуть или навести указатель мыши на каждый маркер на линейной диаграмме, отображающей значение этой конкретной точки.

Чтобы сделать это, мне нужно получить доступ к маркерным элементам объекта 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.


person user3897208    schedule 06.05.2015    source источник
comment
Попробуйте перебрать векторы x и y, которые вы передали plot (или zip(x,y)). Это те точки, к которым вы все равно хотите добавить gids, да?   -  person cphlewis    schedule 06.05.2015
comment
Я знаю, что это можно сделать на интерактивном сюжете matplotlib. Как это сделать в SVG? Можете указать пример?   -  person user3897208    schedule 06.05.2015
comment
matplotlib.org/stable/gallery/user_interfaces/   -  person Justin    schedule 06.08.2021


Ответы (2)


Я изменил код в 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")
person tomatoeshift    schedule 21.11.2020

Лучшим решением вашей проблемы может быть библиотека Charts. Он позволяет использовать превосходную библиотеку JavaScript Highcharts для создания красивых и интерактивных графиков. Highcharts использует тег HTML svg.

По умолчанию все диаграммы будут иметь интерактивные всплывающие подсказки!

Отказ от ответственности: я являюсь разработчиком библиотеки.

person arnoutaertgeerts    schedule 22.05.2015