Matplotlib, что строить в цикле с пользовательским вводом

#python #matplotlib

Вопрос:

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

Я вынужден использовать функцию построения графика matplotlib в коде, который я сейчас пишу, из-за структуры данных, с которой я работаю. Но это плохо сочетается с построением графиков в циклах. Что я хочу сделать со своим сюжетом, так это иметь возможность изменять фоновое окно, определенное пользователем, и либо принимать, либо отклонять вывод. Но, как я понимаю, существует некоторый конфликт между интерактивной функцией matplotlibs и использованием цикла. Я относительно новичок в python, поэтому код, возможно, не самый прихотливый, но обычно я выполняю свою работу. Однако я нахожусь в полной растерянности по поводу конкретной проблемы. Я видел аналогичные проблемы в Интернете, которые были решены с помощью plt.pause («timeinterval»), но в моем случае это не вариант. или, по крайней мере, я не вижу, как я могу его использовать, так как я хочу дождаться ввода пользователя. Я также пробовал plt.waitforbuttonpress (), но это не очень интуитивно, я не могу выбрать, какую кнопку он должен ждать.

Я предполагаю, что третий вариант-извлечь данные из формата, используемого hyperspy, а затем создать свой собственный холст, который удовлетворяет моим потребностям, но это очень удобно для меня из-за отсутствия опыта.

У кого-нибудь есть какие-либо альтернативные способы создания сюжета, предпочтительно с помощью matplotlib, чтобы я мог достичь того, что я пытаюсь?

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

Некоторая информация о спецификациях: Это работает на ПК с Windows, используя jupyterlab и python 3.10

Я надеюсь, что моя дилемма ясна.

 def set_background(self):
    """
    This function is ment to let the user define the background of each element, and then save the background for later use
    if working with multiple images of particles with the same composition.
    This function could be expanded to have interactive features so background would be clickable.
    """
    
    
    self.Background_tree = {}
    elements_in_sample = deepcopy(self.Data.metadata.Sample['elements'])
    Xray_in_sample = self.weighted_Xray_line_list
    data_sample = deepcopy(self.Data)
    integration_window = 1.3
    for element in elements_in_sample:
        data_sample.set_elements(elements=[element])
        for xray_line in (self.Data.metadata.Sample["xray_lines"]):
            if element in xray_line:   
                data_sample.set_lines([xray_line])
                background_points = input('please input the background points seperated by a space').split(' ')
                background_window = list(map(float,background_points))
                bw = data_sample.estimate_background_windows(background_window)
                iw = data_sample.estimate_integration_windows(integration_window)
                data_sample.sum().plot(True,bakcground_windows=background_window)
                happy = input('are you happy with the result?')
                if happy == 'y':
                #self.Data.get_lines_intensity(xray_lines=[xray_line], background_windows=bw, integration_windows=iw)
                    self.Background_tree[element "_" xray_line] = bw  
 

Комментарии:

1. ты проверял ipywidgets ?

2. Спасибо вам за ваш комментарий. Не похоже, что это может удовлетворить то, что я ищу. Проблема в том, что функция построения matplotlib выходит из строя при использовании в цикле, поэтому я не могу заставить пользователя работать с входными данными и видеть добавленные отдельные фоны. Я вынужден использовать функцию построения matplotlib из-за интеграции matplotlib в hyperspy(модуль, с которым я работаю).

3. ipywidgets произойдет сбой input , но будет работать просто отлично labels (что в основном почти одно и то же). И часть построения графика все равно нужно будет выполнить с помощью matplotlib . Я опубликую ответ, используя ipywidgets его, чтобы дать вам больше информации о том, как это будет выглядеть. Я удалю его позже, если он вас не удовлетворит

Ответ №1:

 import pandas as pd
import numpy as np
import ipywidgets as wg
from ipywidgets import HBox, VBox
import matplotlib.pyplot as plt
from IPython.display import display
%matplotlib widget

a = np.arange(50)
b = np.random.rand(50)   a
c = np.sin(a)
d = np.cos(b)

df = pd.DataFrame({'a': a,
                   'b': b,
                   'c': c,
                   'd': d})

userinput1 = wg.Text(value="", placeholder='Type something', description='x axis')
userinput2 = wg.Text(value="", placeholder='Type something', description='y axis')
buttonplot = wg.Button(description='Plot', disabled=False, button_style='', tooltip='Click me',icon='check')
buttonout = wg.Output()
display(HBox((userinput1, userinput2, buttonplot)))
display(buttonout)
plt.close()
fig, ax = plt.subplots()
def on_click_event(change):
    with buttonout:
        x = (userinput1.value)
        y = (userinput2.value)
        ax.plot(df[x], df[y], label=f'{y}')
        ax.legend()
buttonplot.on_click(on_click_event)
 

Выход:

введите описание изображения здесь

После ввода пользователем и нажатия кнопки:

введите описание изображения здесь

Больше пользовательского ввода:

введите описание изображения здесь

Удовлетворяет ли это вашу потребность, или я все больше удаляюсь от вашего первоначального вопроса?

Комментарии:

1. Я думаю, что что-то в этом роде-это именно то, что мне нужно. На первый взгляд может быть трудно понять, будет ли это работать, так как я уже использую некоторые методы из довольно большого модуля (Hyperspy), но, похоже, это можно сделать таким образом. Спасибо вам за ваш ответ !

2. Рад помочь. Я забыл добавить импорт. Теперь это добавлено. В принципе ipywidgets , это не медленно. matplotlib само по себе это уже медленно, от добавления хуже не становится ipywidgets .