Как я могу показать прошлые данные на моем графике Flaskr / Javascript? - PullRequest
0 голосов
/ 18 ноября 2018

Я создаю веб-приложение Flaskr. Из моего бэкэнда Flask я отправляю некоторые данные, которые отображаются на веб-странице с помощью веб-интерфейса Javascript. Данные отправляются через SocketIO.

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

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

Вот как выглядит клиент Flask:

from flask_socketio import SocketIO, emit
from flask import Flask, render_template, url_for, copy_current_request_context
from random import random
from time import sleep
from threading import Thread, Event


__author__ = 'slynn'

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True

#turn the flask app into a socketio app
socketio = SocketIO(app)

#random number Generator Thread
thread = Thread()
thread_stop_event = Event()


class RandomThread(Thread):
    def __init__(self):
        self.delay = 1
        super(RandomThread, self).__init__()

    def randomNumberGenerator(self):
        """
        Generate a random number every 1 second and emit to a socketio instance (broadcast)
        Ideally to be run in a separate thread?
        """
        #infinite loop of magical random numbers
        print("Making random numbers")
        while not thread_stop_event.isSet():
            number = round(random()*10, 3)
            print(number)
            socketio.emit('newnumber', {'number': number}, namespace='/test')
            sleep(self.delay)

    def run(self):
        self.randomNumberGenerator()


@app.route('/')
def index():
    #only by sending this page first will the client be connected to the socketio instance
    return render_template('index.html')

@socketio.on('connect', namespace='/test')
def test_connect():
    # need visibility of the global thread object
    global thread
    print('Client connected')

    #Start the random number generator thread only if the thread has not been started before.
    if not thread.isAlive():
        print("Starting Thread")
        thread = RandomThread()
        thread.start()

@socketio.on('disconnect', namespace='/test')
def test_disconnect():
    print('Client disconnected')





if __name__ == '__main__':
    socketio.run(app)

И вот как выглядит часть Javascript / Chart:

   $(document).ready(function() {
  //connect to the socket server.
  var socket = io.connect('http://' + document.domain + ':' + location.port + '/test');
  var numbers_received = [];


  //receive details from server
  socket.on('newnumber', function(msg) {
    console.log("Received" + msg.number);
    //maintain a list of ten numbers
    if (numbers_received.length >= 1) {
      numbers_received.shift()
    }


    numbers_received.push(msg.number);
    numbers_string = '';
    for (var i = 0; i < numbers_received.length; i++) {
      numbers_string = numbers_string + '<p>' + numbers_received[i].toString() + '</p>';
    }
    $('#log').html(numbers_string);
  });



  function getData() {


    }
    Plotly.plot('chart',[{
        y:[numbers_received[1]],
        type:'line'
        }]);

        console.log('TEST' + numbers_received[0]);

        var cnt = 0;
        setInterval(function(){
        Plotly.extendTraces('chart',{ y:[[numbers_received[0]]]}, [0]);

        cnt++;

        if(cnt >10000000) {
            Plotly.relayout('chart',{
                xaxis: {
                    range: [cnt-9,cnt]
                    }
                });
            }
    },15);

});

index.html

<!DOCTYPE html>
<html>
<head>
    <script src="//code.jquery.com/jquery-3.3.1.min.js"></script>
    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
    <script src="static/js/application.js"></script>

    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">


    <script src="https://cdn.plot.ly/plotly-latest.js" charset="utf-8"></script>

    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>


</head>
<body>

<div class="container">
  <div class="jumbotron">
    <h1>Asynchronous Flask Communication</h1>
    <p>Random numbers generated by the Flask server will appear below, asynchronously.</p>
    <p>Details <a href='https://www.shanelynn.ie/asynchronous-updates-to-a-webpage-with-flask-and-socket-io/' target='_blank'>here.</a></p>
  </div>
</div>


<div class="container" id="content">
    <div class="row">
        <p>Asynchronous page updates will appear here:</p>
        <h3>Number list:</h3>
        <div id="log">
    </div>
</div>

<div id="chart"></div>

</body>
</html>

1 Ответ

0 голосов
/ 20 ноября 2018

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

Текущая ситуация:

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

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

Технические трудности, которыми он обладает:

  • решение должно синхронизироваться на полпути, в то время как клиенты получают старые данные через JSON или что-то еще, вы все равно должны выровнять после построение и выполнять снова и снова функцию синхронизации, пока не достигает того же уровня, что и текущий генерируемый номер.
  • вы должны каким-либо образом управлять как предыдущим, так и текущим сгенерированным фидом для всех клиентов (если в теории один не будет подключен, API запускается и получает канал с первого).

Возможные, теоретические решения вашей проблемы - это не только инструменты реального времени, такие как https://www.rethinkdb.com/,, но и понятия данных at-rest для ранее сгенерированных чисел. Опять же, теоретически вам придется вызывать рекурсивную функцию для:

  • для каждого сгенерированного номера вы можете назначить временную метку для сравнения с текущей или имеющейся у вас и узнать, будет ли она выше или ниже.
  • выводит на экран старые данные, собранные и сохраненные на сервере и передаваемые при первоначальном подключении.
  • выводит на экран данные, сгенерированные в то время, когда вы строите самый старый (эти партии генерируются к моменту подключения, пока вы не закончили старые)
  • построить данные, полученные во время второго построения.
  • проверьте, достигли ли вы текущей головы.
  • повторить || если голова, то продолжай строить только самые последние.
  • функция, которая строит график, должна иметь возможность обрабатывать список или одно число, таким образом, поддерживая в обоих случаях, когда позади и когда она получает один.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...