如何在Flaskr / Javascript图表上显示过去的数据?

时间:2018-11-17 22:24:19

标签: javascript python flask charts

我正在构建Flaskr Web应用程序。我从Flask后端发送一些数据,这些数据显示在带有Java前端的网页上。数据通过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 /图表部分的样子:

   $(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 :(得分:2)

仅传递一个数字而不使用中央同步的问题是,当您收到旧的历史记录并对其进行处理时,API已经生成了新的数字,所以真正的任务是如何将当前状态或数字与即使您设法传递历史记录,也可以实时地实时生成以前的记录。

当前情况:

  • 您从API变成那一刻起就开始生成随机数 活着。
  • 客户端通过套接字与API连接后立即获取实时供稿,然后从当前编号读取供稿, 直到断开连接。
  • 先前生成的号码未提供/提供给任何客户。
  • 如果客户端连接的读取在一段时间内关闭,然后又重新连接,则它将从该当前点开始绘图。

在这种情况下,您需要让客户获得之前生成的所有编号,并在开始读取当前生成的编号之前对其进行绘图。

它带来的技术困难:

  • 解决方案应该在中途同步,而客户端会收到旧的 JSON或其他格式的数据,之后您仍然需要对齐 绘图并一次又一次执行同步功能,直到它 达到与当前生成的数字相同的水平。
  • 您必须以一种方式管理所有客户的以前和当前生成的提要(除非理论上除非一个人尽快连接) API就会启动并从第一个API获取提要。

可能的,理论上解决您的问题的方法不仅是像https://www.rethinkdb.com/这样的实时工具,而且还是先前生成的数字的数据at-rest的概念。同样,从理论上讲,您必须调用递归函数以:

  • 在每个生成的数字上,您都可以分配时间戳,以便与当前或您拥有的时间戳进行比较,并知道它是更高还是更低。
  • 绘制收集并存储到服务器中的旧数据,并在初始连接时进行提要。
  • 绘制在绘制最旧的数据时生成的数据(这些批次是从连接的那一刻起直到完成旧数据的那一刻生成的)
  • 绘制第二次绘制期间生成的数据。
  • 检查您是否达到目前的水平。
  • 重复||如果是头,则继续只绘制最新的图。
  • 绘图功能应该能够处理列表或单个数字,从而在后面和接收到单个情况时都支持这两种情况。