Plotly (офлайн) для события щелчка Python

Можно ли добавить события кликов на точечный график Plotly (автономный режим в Python)?

В качестве примера я хочу изменить форму набора точек разброса при нажатии.

Что я уже пробовал

Насколько я понял из чтения других вопросов с сайта (без четкого ответа), мне, возможно, придется создать html, а затем отредактировать его постфактум, вставив код javascript? Итак, я мог бы написать функцию javascript, сохранить ее в my_js.js, а затем сослаться на нее из html?


person denvar    schedule 12.01.2017    source источник


Ответы (2)


Я немного поработал с автономными сюжетами в сюжете, и у меня была такая же проблема.

Вот кладж, который я придумал, который может служить источником вдохновения для других.

Некоторые ограничения:

  • Предполагается, что у вас есть автономный вывод в одном HTML-файле для одного графика.
  • Предполагается, что ваши события on называются так же, как и обработчики событий.
  • Требуется Красивый суп 4.
  • Предполагается, что у вас установлен lxml.
  • Разработано с помощью Plotly 2.2.2

Фрагмент кода:

import bs4

def add_custom_plotly_events(
    filename, 
    events = {
        "plotly_click": "function plotly_click(data) { console.log(data); }",
        "plotly_hover": "function plotly_hover(data) { console.log(data); }"
    },
    prettify_html = True
):

    # what the value we're looking for the javascript
    find_string = "Plotly.newPlot"

    # stop if we find this value
    stop_string = "then(function(myPlot)"

    def locate_newplot_script_tag(soup):    
        scripts = soup.find_all('script')
        script_tag = soup.find_all(string=re.compile(find_string))

        if len(script_tag) == 0:
            raise ValueError("Couldn't locate the newPlot javascript in {}".format(filename))
        elif len(script_tag) > 1:
            raise ValueError("Located multiple newPlot javascript in {}".format(filename))

        if script_tag[0].find(stop_string) > -1:
            raise ValueError("Already updated javascript, it contains:", stop_string)

        return script_tag[0]

    def split_javascript_lines(new_plot_script_tag):
        return new_plot_script_tag.string.split(";")

    def find_newplot_creation_line(javascript_lines):
        for index, line in enumerate(javascript_lines):
            if line.find(find_string) > -1:
                return index, line
        raise ValueError("Missing new plot creation in javascript, couldn't find:", find_string)

    def join_javascript_lines(javascript_lines):
        # join the lines with javascript line terminator ;    
        return ";".join(javascript_lines)

    def register_on_events(events):
        on_events_registration = []
        for function_name in events:
            on_events_registration.append("myPlot.on('{}', {})".format(
                function_name, function_name
            ))
        return on_events_registration

    # load the file
    with open(filename) as inf:
        txt = inf.read()
        soup = bs4.BeautifulSoup(txt, "lxml")

    new_plot_script_tag = locate_newplot_script_tag(soup)

    javascript_lines = split_javascript_lines(new_plot_script_tag)

    line_index, line_text = find_newplot_creation_line(javascript_lines)    

    on_events_registration = register_on_events(events)

    # replace whitespace characters with actual whitespace
    # using + to concat the strings as {} in format
    # causes fun times with {} as the brackets in js
    # could possibly overcome this with in ES6 arrows and such
    line_text = line_text + ".then(function(myPlot) { " + join_javascript_lines(on_events_registration) +"  })".replace('\n', ' ').replace('\r', '')

    # now add the function bodies we've register in the on handles
    for function_name in events:
        javascript_lines.append(events[function_name])

    # update the specific line
    javascript_lines[line_index] = line_text

    # update the text of the script tag
    new_plot_script_tag.string.replace_with(join_javascript_lines(javascript_lines))

    # save the file again
    with open(filename, "w") as outf:
        # tbh the pretty out is still ugly af
        if prettify_html:
            for line in soup.prettify(formatter = None):
                outf.write(str(line))
        else:
            outf.write(str(soup))
person Ryan Collingwood    schedule 05.07.2018
comment
Как вы используете эту функцию? Если бы вы могли показать (базовый) пример, это было бы здорово! - person Kristada673; 17.05.2019
comment
В рамках процесса генерации отчета у меня было несколько графиков рассеяния (агрегации состояний и агрегации областей ниже состояния), которые были сгенерированы. Мне нужно было, чтобы они были офлайн-сюжетами из-за забавных времен брандмауэра. Я использовал щелчок, чтобы перемещаться между агрегацией на уровне штата, чтобы перейти к агрегации на уровне области. - person Ryan Collingwood; 20.05.2019

Согласно События кликов в автономном режиме Python? на сайте сообщества Plotly это не поддерживается, по крайней мере, с декабря 2015 года.

Этот пост содержит некоторые подсказки о том, как реализовать эту функциональность самостоятельно, если вы чувствуете себя предприимчивым.

person Jason Sundram    schedule 19.04.2017