Сценарий Python останавливается при запуске plt.show из matplotlib.pyplot [duplicate]

Проверьте, что элемент виден в окне просмотра без плагина:

Сначала определите верхнее и нижнее положения элемента. Затем определите положение нижней части окна просмотра (относительно верхней части страницы), добавив положение прокрутки в высоту окна просмотра.

Если нижнее положение окна просмотра больше, чем верхнее положение элемента, и верхнее положение окна просмотра меньше, чем нижнее положение элемента, элемент находится в окне просмотра (по крайней мере частично). Проще говоря, когда какая-либо часть элемента находится между верхней и нижней границами вашего окна просмотра, элемент отображается на вашем экране.

Теперь вы можете написать оператор if / else, где оператор if выполняется только при выполнении вышеуказанного условия.

В приведенном ниже коде выполняется то, что было описано выше:

//this function runs every time you are scrolling

$(window).scroll(function() {
    var top_of_element = $("#element").offset().top;
    var bottom_of_element = $("#element").offset().top + $("#element").outerHeight();
    var bottom_of_screen = $(window).scrollTop() + window.innerHeight;
    var top_of_screen = $(window).scrollTop();

    if((bottom_of_screen > top_of_element) && (top_of_screen < bottom_of_element)){
        // The element is visible, do something
    }
    else {
        // The element is not visible, do something else
    }
});

Этот ответ представляет собой краткое изложение того, что обсуждали далее Крис Бир и Энди. Надеюсь, это поможет кому-то еще, кто сталкивается с этим вопросом во время исследований, как я. Я также использовал ответ на следующий вопрос, чтобы сформулировать свой ответ: Показывать Div при прокрутке позиции .

156
задан Chris 9 August 2012 в 00:44
поделиться

10 ответов

Вот рабочая версия рассматриваемого кода (требуется, по крайней мере, версия Matplotlib 1.1.0 с 2011-11-14):

import numpy as np
import matplotlib.pyplot as plt

plt.axis([0, 10, 0, 1])

for i in range(10):
    y = np.random.random()
    plt.scatter(i, y)
    plt.pause(0.05)

plt.show()

Обратите внимание на некоторые изменения:

  1. Вызовите plt.pause(0.05) для вывода новых данных, и он запускает цикл событий GUI (что позволяет взаимодействовать с мышью).
213
ответ дан Hritik 20 August 2018 в 16:17
поделиться
  • 1
    Это сработало для меня в Python2. В Python3 это не так. После создания окна графика он приостанавливает цикл. Но после перемещения метода plt.show () после цикла ... он разрешил его для Python3, для меня. – continuousqa 5 September 2014 в 19:36
  • 2
    Weird, работал хорошо для меня в Python 3 (ver 3.4.0) Matplotlib (версия 1.3.1) Numpy (версия 1.8.1) Ubuntu Linux 3.13.0 64-разрядная – Velimir Mlaker 12 September 2014 в 15:58
  • 3
    вместо plt.show () и plt.draw () просто замените plt.draw () на plt.pause (0.1) – denfromufa 25 September 2014 в 23:17
  • 4
    Не работает на Win64 / Anaconda matplotlib .__ version__ 1.5.0. Начальное окно фигуры открылось, но ничего не отображалось, оно оставалось в заблокированном состоянии, пока я не закрыл его – isti_spl 4 February 2016 в 09:39
  • 5
    Этот ответ требует априорного знания данных x / y ... который не нужен: я предпочитаю 1. не вызывайте plt.axis(), а вместо этого создавайте два списка x и y и вызывайте plt.plot(x,y) 2. в своем цикле , добавьте новые значения данных в два списка. 3. вызовите plt.gca().lines[0].set_xdata(x); plt.gca().lines[0].set_ydata(y); plt.gca().relim(); plt.gca().autoscale_view(); plt.pause(0.05); – Trevor Boyd Smith 13 April 2016 в 18:09

Если вы заинтересованы в построении в реальном времени, я бы рекомендовал заглянуть в анимационный API matplotlib . В частности, использование blit во избежание перерисовки фона на каждом кадре может дать вам существенную прирост скорости (~ 10x):

#!/usr/bin/env python

import numpy as np
import time
import matplotlib
matplotlib.use('GTKAgg')
from matplotlib import pyplot as plt


def randomwalk(dims=(256, 256), n=20, sigma=5, alpha=0.95, seed=1):
    """ A simple random walk with memory """

    r, c = dims
    gen = np.random.RandomState(seed)
    pos = gen.rand(2, n) * ((r,), (c,))
    old_delta = gen.randn(2, n) * sigma

    while True:
        delta = (1. - alpha) * gen.randn(2, n) * sigma + alpha * old_delta
        pos += delta
        for ii in xrange(n):
            if not (0. <= pos[0, ii] < r):
                pos[0, ii] = abs(pos[0, ii] % r)
            if not (0. <= pos[1, ii] < c):
                pos[1, ii] = abs(pos[1, ii] % c)
        old_delta = delta
        yield pos


def run(niter=1000, doblit=True):
    """
    Display the simulation using matplotlib, optionally using blit for speed
    """

    fig, ax = plt.subplots(1, 1)
    ax.set_aspect('equal')
    ax.set_xlim(0, 255)
    ax.set_ylim(0, 255)
    ax.hold(True)
    rw = randomwalk()
    x, y = rw.next()

    plt.show(False)
    plt.draw()

    if doblit:
        # cache the background
        background = fig.canvas.copy_from_bbox(ax.bbox)

    points = ax.plot(x, y, 'o')[0]
    tic = time.time()

    for ii in xrange(niter):

        # update the xy data
        x, y = rw.next()
        points.set_data(x, y)

        if doblit:
            # restore background
            fig.canvas.restore_region(background)

            # redraw just the points
            ax.draw_artist(points)

            # fill in the axes rectangle
            fig.canvas.blit(ax.bbox)

        else:
            # redraw everything
            fig.canvas.draw()

    plt.close(fig)
    print "Blit = %s, average FPS: %.2f" % (
        str(doblit), niter / (time.time() - tic))

if __name__ == '__main__':
    run(doblit=False)
    run(doblit=True)

Выход:

Blit = False, average FPS: 54.37
Blit = True, average FPS: 438.27
55
ответ дан ali_m 20 August 2018 в 16:17
поделиться
  • 1
    Это выглядит красиво, но где вы на самом деле называете & quot; show & quot; или отобразить график? – bejota 30 January 2015 в 22:37
  • 2
    @bejota Оригинальная версия была разработана для работы в интерактивном сеансе matplotlib. Чтобы заставить его работать как отдельный сценарий, необходимо: 1) явно выбрать бэкэнд для matplotlib и 2) заставить фигуру отображать и рисовать перед входом в цикл анимации с помощью plt.show() и plt.draw(). Я добавил эти изменения в код выше. – ali_m 2 February 2015 в 11:41
  • 3
    Большое спасибо! Я собираюсь это время пережевывать. У меня есть несколько осей и диапазонов осей, которые также меняются. – bejota 3 February 2015 в 00:44
  • 4
    Является ли намерение / мотивация blit(), похоже, очень «улучшением графика в реальном времени»? Если у вас есть разработчик / блог matplotlib, обсуждающий, почему / цель / намерение / мотивация были бы замечательными. (похоже, что эта новая blit-операция превратит Matplotlib только для автономных или очень медленно меняющихся данных, теперь вы можете использовать Matplotlib с очень быстрыми данными по обновлению ... почти как осциллограф). – Trevor Boyd Smith 14 April 2016 в 13:43
  • 5
    Я обнаружил, что этот подход делает окно сюжета невосприимчивым: я не могу с ним взаимодействовать, и это может привести к его краху. – Ninjakannon 29 December 2016 в 05:44

show, вероятно, не лучший выбор для этого. Вместо этого я буду использовать pyplot.draw(). Вы также можете включить небольшую задержку (например, time.sleep(0.05)) в цикле, чтобы вы могли видеть сюжеты. Если я сделаю эти изменения в вашем примере, это сработает для меня, и я вижу, что каждый пункт появляется по одному.

31
ответ дан BrenBarn 20 August 2018 в 16:17
поделиться
  • 1
    У меня очень похожая часть кода, и когда я пытаюсь выполнить ваше решение (рисовать вместо показа и задержки), python вообще не открывает окно с рисунком, просто проходит через цикл ... – George Aprilis 31 January 2016 в 23:02

Ни один из методов не работал для меня. Но я нашел, что это . Графический график matplotlib в реальном времени не работает, пока он все еще находится в цикле

. Все, что вам нужно, это добавить

plt.pause(0.0001)

и чем вы мог видеть новый сюжет.

Итак, ваш код должен выглядеть так, и он будет работать

import matplotlib.pyplot as plt
import numpy as np
plt.ion() ## Note this correction
fig=plt.figure()
plt.axis([0,1000,0,1])

i=0
x=list()
y=list()

while i <1000:
    temp_y=np.random.random();
    x.append(i);
    y.append(temp_y);
    plt.scatter(i,temp_y);
    i+=1;
    plt.show()
    plt.pause(0.0001) #Note this correction
26
ответ дан Community 20 August 2018 в 16:17
поделиться
  • 1
    это правильный ответ, добавьте этот plt.pause (0.0001) – Isopycnal Oscillation 17 August 2014 в 06:30
  • 2
    Это открывает каждый раз новое окно фигуры / графика для меня, есть ли способ просто обновить существующую цифру? возможно, потому что я использую imshow? – Francisco Vargas 26 January 2016 в 03:27
  • 3
    @FranciscoVargas, если вы используете imshow, вам нужно использовать set_data, посмотрите здесь: stackoverflow.com/questions/17835302/… – Oren 11 December 2016 в 08:14

Верхний (и многие другие) ответы были построены на plt.pause(), но это был старый способ анимации сюжета в matplotlib.

TL; DR: вы можете захотеть использовать matplotlib.animation (, как указано в документации ).

После того, как вы разыграли различные ответы и фрагменты кода, на самом деле это был плавный способ бесконечного рисования входящих данных.

Вот мой код для быстрого запуска. Он отображает текущее время со случайным числом в [0, 100) каждые 200 мс бесконечно, одновременно обрабатывая автоматическое масштабирование вида:

from datetime import datetime
from matplotlib import pyplot
from matplotlib.animation import FuncAnimation
from random import randrange

x_data, y_data = [], []

figure = pyplot.figure()
line, = pyplot.plot_date(x_data, y_data, '-')

def update(frame):
    x_data.append(datetime.now())
    y_data.append(randrange(0, 100))
    line.set_data(x_data, y_data)
    figure.gca().relim()
    figure.gca().autoscale_view()
    return line,

animation = FuncAnimation(figure, update, interval=200)

pyplot.show()

Вы также можете исследовать blit для еще большей производительности , как в документации FuncAnimation .

4
ответ дан Dreaming in Code 20 August 2018 в 16:17
поделиться

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

###################################################################
#                                                                 #
#                     PLOTTING A LIVE GRAPH                       #
#                  ----------------------------                   #
#            EMBED A MATPLOTLIB ANIMATION INSIDE YOUR             #
#            OWN GUI!                                             #
#                                                                 #
###################################################################


import sys
import os
from PyQt4 import QtGui
from PyQt4 import QtCore
import functools
import numpy as np
import random as rd
import matplotlib
matplotlib.use("Qt4Agg")
from matplotlib.figure import Figure
from matplotlib.animation import TimedAnimation
from matplotlib.lines import Line2D
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import time
import threading



def setCustomSize(x, width, height):
    sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(x.sizePolicy().hasHeightForWidth())
    x.setSizePolicy(sizePolicy)
    x.setMinimumSize(QtCore.QSize(width, height))
    x.setMaximumSize(QtCore.QSize(width, height))

''''''

class CustomMainWindow(QtGui.QMainWindow):

    def __init__(self):

        super(CustomMainWindow, self).__init__()

        # Define the geometry of the main window
        self.setGeometry(300, 300, 800, 400)
        self.setWindowTitle("my first window")

        # Create FRAME_A
        self.FRAME_A = QtGui.QFrame(self)
        self.FRAME_A.setStyleSheet("QWidget { background-color: %s }" % QtGui.QColor(210,210,235,255).name())
        self.LAYOUT_A = QtGui.QGridLayout()
        self.FRAME_A.setLayout(self.LAYOUT_A)
        self.setCentralWidget(self.FRAME_A)

        # Place the zoom button
        self.zoomBtn = QtGui.QPushButton(text = 'zoom')
        setCustomSize(self.zoomBtn, 100, 50)
        self.zoomBtn.clicked.connect(self.zoomBtnAction)
        self.LAYOUT_A.addWidget(self.zoomBtn, *(0,0))

        # Place the matplotlib figure
        self.myFig = CustomFigCanvas()
        self.LAYOUT_A.addWidget(self.myFig, *(0,1))

        # Add the callbackfunc to ..
        myDataLoop = threading.Thread(name = 'myDataLoop', target = dataSendLoop, daemon = True, args = (self.addData_callbackFunc,))
        myDataLoop.start()

        self.show()

    ''''''


    def zoomBtnAction(self):
        print("zoom in")
        self.myFig.zoomIn(5)

    ''''''

    def addData_callbackFunc(self, value):
        # print("Add data: " + str(value))
        self.myFig.addData(value)



''' End Class '''


class CustomFigCanvas(FigureCanvas, TimedAnimation):

    def __init__(self):

        self.addedData = []
        print(matplotlib.__version__)

        # The data
        self.xlim = 200
        self.n = np.linspace(0, self.xlim - 1, self.xlim)
        a = []
        b = []
        a.append(2.0)
        a.append(4.0)
        a.append(2.0)
        b.append(4.0)
        b.append(3.0)
        b.append(4.0)
        self.y = (self.n * 0.0) + 50

        # The window
        self.fig = Figure(figsize=(5,5), dpi=100)
        self.ax1 = self.fig.add_subplot(111)


        # self.ax1 settings
        self.ax1.set_xlabel('time')
        self.ax1.set_ylabel('raw data')
        self.line1 = Line2D([], [], color='blue')
        self.line1_tail = Line2D([], [], color='red', linewidth=2)
        self.line1_head = Line2D([], [], color='red', marker='o', markeredgecolor='r')
        self.ax1.add_line(self.line1)
        self.ax1.add_line(self.line1_tail)
        self.ax1.add_line(self.line1_head)
        self.ax1.set_xlim(0, self.xlim - 1)
        self.ax1.set_ylim(0, 100)


        FigureCanvas.__init__(self, self.fig)
        TimedAnimation.__init__(self, self.fig, interval = 50, blit = True)

    def new_frame_seq(self):
        return iter(range(self.n.size))

    def _init_draw(self):
        lines = [self.line1, self.line1_tail, self.line1_head]
        for l in lines:
            l.set_data([], [])

    def addData(self, value):
        self.addedData.append(value)

    def zoomIn(self, value):
        bottom = self.ax1.get_ylim()[0]
        top = self.ax1.get_ylim()[1]
        bottom += value
        top -= value
        self.ax1.set_ylim(bottom,top)
        self.draw()


    def _step(self, *args):
        # Extends the _step() method for the TimedAnimation class.
        try:
            TimedAnimation._step(self, *args)
        except Exception as e:
            self.abc += 1
            print(str(self.abc))
            TimedAnimation._stop(self)
            pass

    def _draw_frame(self, framedata):
        margin = 2
        while(len(self.addedData) > 0):
            self.y = np.roll(self.y, -1)
            self.y[-1] = self.addedData[0]
            del(self.addedData[0])


        self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ])
        self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin]))
        self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin])
        self._drawn_artists = [self.line1, self.line1_tail, self.line1_head]



''' End Class '''


# You need to setup a signal slot mechanism, to 
# send data to your GUI in a thread-safe way.
# Believe me, if you don't do this right, things
# go very very wrong..
class Communicate(QtCore.QObject):
    data_signal = QtCore.pyqtSignal(float)

''' End Class '''



def dataSendLoop(addData_callbackFunc):
    # Setup the signal-slot mechanism.
    mySrc = Communicate()
    mySrc.data_signal.connect(addData_callbackFunc)

    # Simulate some data
    n = np.linspace(0, 499, 500)
    y = 50 + 25*(np.sin(n / 8.3)) + 10*(np.sin(n / 7.5)) - 5*(np.sin(n / 1.5))
    i = 0

    while(True):
        if(i > 499):
            i = 0
        time.sleep(0.1)
        mySrc.data_signal.emit(y[i]) # <- Here you emit a signal!
        i += 1
    ###
###




if __name__== '__main__':
    app = QtGui.QApplication(sys.argv)
    QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Plastique'))
    myGUI = CustomMainWindow()


    sys.exit(app.exec_())

''''''

Просто попробуйте. Скопируйте этот код в новый файл python и запустите его. Вы должны получить красивый, плавно движущийся график:

23
ответ дан K.Mulier 20 August 2018 в 16:17
поделиться
  • 1
    Я заметил, что поток dataSendLoop продолжал работать в фоновом режиме при закрытии окна. Поэтому я решил добавить ключевое слово daemon = True, чтобы решить эту проблему. – K.Mulier 26 September 2016 в 09:21
  • 2
    Виртуальная среда для этого заняла немного времени. Наконец, conda install pyqt=4 сделал трюк. – Reb.Cabin 29 June 2018 в 04:20

Проблема заключается в том, что вы ожидаете, что plt.show() отобразит окно, а затем вернется. Это не так. Программа остановится в этот момент и возобновится только после закрытия окна. Вы должны проверить это: если вы закроете окно, а затем появится другое окно.

Чтобы решить эту проблему, просто вызовите plt.show() один раз после вашего цикла. Затем вы получите полный сюжет. (Но не «построение в реальном времени»)

Вы можете попробовать установить ключевое слово-аргумент block следующим образом: plt.show(block=False) один раз в начале, а затем использовать .draw() для обновления.

5
ответ дан Michael Mauderer 20 August 2018 в 16:17
поделиться
  • 1
    в реальном времени графика действительно то, что я собираюсь. Я собираюсь провести 5-часовой тест на что-то и хочу посмотреть, как все развивается. – Chris 9 August 2012 в 00:48
  • 2
    @ Крис, вы могли провести 5-часовой тест? Я также ищу что-то подобное. Я использую plyplot.pause (time_duration) для обновления графика. Есть ли другой способ сделать это? – Prakhar Mohan Srivastava 11 April 2014 в 17:02

Я знаю, что этот вопрос старый, но теперь есть доступный пакет под названием drawow на GitHub как «python-drawow». Это дает интерфейс, подобный приводу MATLAB - вы можете легко обновить фигуру.

Пример для вашего варианта использования:

import matplotlib.pyplot as plt
from drawnow import drawnow

def make_fig():
    plt.scatter(x, y)  # I think you meant this

plt.ion()  # enable interactivity
fig = plt.figure()  # make a figure

x = list()
y = list()

for i in range(1000):
    temp_y = np.random.random()
    x.append(i)
    y.append(temp_y)  # or any arbitrary update to your figure's data
    i += 1
    drawnow(make_fig)

python- drawow - тонкая обертка вокруг plt.draw, но обеспечивает возможность подтверждения (или отладки) после отображения фигуры.

9
ответ дан Scott 20 August 2018 в 16:17
поделиться

Вот версия, которую я получил для работы в моей системе.

import matplotlib.pyplot as plt
from drawnow import drawnow
import numpy as np

def makeFig():
    plt.scatter(xList,yList) # I think you meant this

plt.ion() # enable interactivity
fig=plt.figure() # make a figure

xList=list()
yList=list()

for i in np.arange(50):
    y=np.random.random()
    xList.append(i)
    yList.append(y)
    drawnow(makeFig)
    #makeFig()      The drawnow(makeFig) command can be replaced
    #plt.draw()     with makeFig(); plt.draw()
    plt.pause(0.001)

Линия pullow (makeFig) может быть заменена на makeFig (); plt.draw (), и он все еще работает нормально.

4
ответ дан slehar 20 August 2018 в 16:17
поделиться
  • 1
    Откуда вы знаете, как долго останавливаться? По-видимому, он зависит от самого сюжета. – CMCDragonkai 17 May 2018 в 06:56

Если вы хотите нарисовать и не замораживать свою нить при увеличении количества точек, вы должны использовать plt.pause () not time.sleep ()

im, используя следующий код, чтобы построить серию координат xy .

import matplotlib.pyplot as plt 
import math


pi = 3.14159

fig, ax = plt.subplots()

x = []
y = []

def PointsInCircum(r,n=20):
    circle = [(math.cos(2*pi/n*x)*r,math.sin(2*pi/n*x)*r) for x in xrange(0,n+1)]
    return circle

circle_list = PointsInCircum(3, 50)

for t in range(len(circle_list)):
    if t == 0:
        points, = ax.plot(x, y, marker='o', linestyle='--')
        ax.set_xlim(-4, 4) 
        ax.set_ylim(-4, 4) 
    else:
        x_coord, y_coord = circle_list.pop()
        x.append(x_coord)
        y.append(y_coord)
        points.set_data(x, y)
    plt.pause(0.01)
1
ответ дан user2672474 20 August 2018 в 16:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: