Постоянное обновление сюжета matplotlib в Юпитере - PullRequest
1 голос
/ 21 октября 2019

Я работаю над Jupyter Notebook и использую следующее ipywidget для установки порогового значения:

Thr = widgets.IntSlider(value=-17, min=-30, max=-13, step=1, description='Threshold: ', disabled=False, continuous_update=True, orientation='horizontal', readout=True, readout_format='d')
Thr

Далее я маскирую numpy array, используя это значение с:

import numpy.ma as ma
test= ma.masked_less_equal(S_images[0], Thr.value)

И, наконец, я отображаю результат с помощью:

plt.figure(figsize = (15,15))
plt.imshow(test[0], cmap='gray')

ipywidget отличается от Jupyter cell от другого кода, поэтому при изменении значения ThrЯ должен вручную снова запустить ячейку, в которой происходит маскирование и создание графиков.

Мой вопрос: я всегда видел те интерактивные графики, в которых вы меняете параметр (в моем случае ipywidget Thr) и автоматическисюжет обновляется.

Я вижу, что widgets.IntSlider имеет параметр continuous_update, который, кажется, близок к тому, что я хочу, но все еще не может получить поведение, которое я хочу.

Любая идея, если это выполнимо или возможно?

_ EDIT _

Начиная с комментария ac24, я адаптирую пример, который он предлагает:

from IPython.display import display, clear_output
import ipywidgets as ipy
import matplotlib.pyplot as plt
import numpy as np

# setup figure
n = 10

out = ipy.Output()

# show random mesh
def update(idx):
    with out:
        clear_output()
        fig, ax = plt.subplots(figsize = (5,5))
        h = ax.imshow(S_images[0]) # here I put my image
        h.set_data(np.ma.masked_less_equal(S_images[0], slider.value)) # here I set the task to masked accordint to the `slider.value`
        fig.canvas.flush_events()
        fig.canvas.draw()
        plt.show()

slider = ipy.IntSlider(min = 0, max = 10, orientation = 'vertical')
widget = ipy.interactive(update, idx = slider)

layout = ipy.Layout(
#     display = 'flex',
#                    flex_flow = 'row',
#                    justify_content = 'space-between',
#                    align_items = 'center',
                   )
widgets = ipy.HBox(children=(slider, out), layout = layout)
display(widgets)

Пример работает очень хорошо и это именно то, что я искал. Тем не менее, у меня есть маленький вопрос по поводу макета. Изначально я работаю с 3-мя изображениями, поэтому мне бы хотелось, чтобы они отображались следующим образом, каждое с ползунком рядом с ним для выполнения задачи: (изображение ниже не является реальным, просто составлено так, чтобы оно представляло то, что я хотел бы)

enter image description here

РЕДАКТИРОВАТЬ 2

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

with rasterio.open('/Path/20190331_VV_Crop') as src:
    ras_meta = src.profile

with rasterio.open('/path/Threshold.tif', 'w', **ras_meta) as dst:
    dst.write(X)

Однако я не уверен, как ссылаться на массив numpy в dst.write(X)

1 Ответ

1 голос
/ 28 октября 2019

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

from IPython.display import display, clear_output
import ipywidgets as ipy
import matplotlib.pyplot as plt
import numpy as np

# setup figure
n = 10

class SliderAndImage():

    # show random mesh
    def update(self, idx):
        with self.out:
            clear_output()
            fig, ax = plt.subplots(figsize = (5,5))
            h = ax.imshow(np.random.rand(n, n))
            h.set_data(np.random.rand(n, n))
            fig.canvas.flush_events()
            fig.canvas.draw()
            plt.show()

    def make_slider_and_image(self):

        self.out = ipy.Output(layout=ipy.Layout(width='200px', height='200px'))

        slider = ipy.IntSlider(min = 0, max = 10, orientation = 'vertical')
        widget = ipy.interactive(self.update, idx = slider)

        layout = ipy.Layout(
        #     display = 'flex',
        #                    flex_flow = 'row',
        #                    justify_content = 'space-between',
        #                    align_items = 'center',
                           )
        widgets = ipy.HBox(children=(slider, self.out), layout = layout)
        return widgets

children = []
for _ in range(3):
    widgets = SliderAndImage()
    children.append(widgets.make_slider_and_image())
display(ipy.HBox(children))

enter image description here

...