По какой-то причине мне нужно передать длинный массив из numpy.ndarray в веб-браузер и отобразить его на графике

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

​// python side
response = json.dumps({ data: long_nd_array.tolist() })
// browser side
let array = json.parse(response).data

Это ужасный способ передачи, замедления и увеличения длины массива. Я должен найти другой способ передачи данных, более надежный. Я много пробовал, в итоге решил передавать в двоичном виде

Сторона сервера

Я заметил, что numpy.ndarray можно легко преобразовать в двоичные данные.

​import numpy as np
x = np.array([1,2,3,4], dtype=np.float32)
binary_array = x.tobytes()

Я использую flask для обслуживания своего проекта. ответ должен настроить application/octet-stream как требуется, это может заставить веб-браузер рассматривать ответ сервера как двоичные данные.

​from flask import make_response
@app.route('/testMyArray')
def test_array():
  x = np.array(my_long_arrray, dtype=np.float32)
  response = make_response(x.tobytes())
  response.headers.set('Content-Type', 'application/octet-stream')
  return response

Сторона браузера

Javascript может хранить двоичные данные с помощью ArrayBuffer и выполнять операции с помощью типизированного массива.

Типизированный массив — это массив фиксированной длины в явном типе, он может быть создан с помощью ArrayBuffer.

Пример фрагмента кода:

​const typedArray = new float32Array(some_array_buffer);

Для запроса XMLHttpRequest может отправить двоичный запрос, установив определенный тип ответа.

​const fetchBinaryArray = () => new Promise((resolve, reject) => {
  let xhr = new XMLhttprequest()
  xhr.open('get', 'http://xxx/test_my_array', true)
  xhr.responseType = 'arraybuffer' // <- specific responseType
  xhr.onLoad = () => {
    if(xhr.status === 200) {
      resolve(xhr.response)
    } else {
      reject()
    }
  }
  xhr.onError = () => { reject() }
  xhr.send()
})

Эта функция может напрямую получить объект типа буфера массива, в котором хранятся двоичные данные ответа.

​fetchBinaryArray().then(arrayBuffer => {
  console.log(arrayBuffer.toString()) // <- [object ArrayBuffer]
  // directly get a arraybuffer
})

Затем для чтения этих данных создайте типизированный массив.

​let myResponseData = new Float32Array(arrayBuffer)

На этом я заканчиваю передачу

УВЕДОМЛЕНИЕ

Тип Typed Array должен совпадать с типом np.ndarray, иначе он будет нечитаемым.

​// python
array = np.array(long_arrya, dtype=np.float32)
// javascript
let array = new Float32Array(arraybuffer)
// 'np.float32' = 'Float32Array'

Затем отобразите его на графике

Echart — это мощная библиотека для работы с большими данными, которая позволяет легко рисовать длинные массивы.

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

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

Всего несколько кодов строк

let myChart = echarts.init(document.getElementById('main'))
myChart.setOption({
  xAxis: { type: 'value' },
  yAxis: { type: 'value' },
  dataset: {
    dimensions:[
      { name: 'x', type: 'float'}, 
      { name: 'y', type: 'float'}
    ],
    source: [
      Array.from(x), Array.from(y)
    ],        
  },
  series: {
    type: 'line',
    sampling: 'max',
    encode: {
      'y': 'y',
      'x': 'x'
    },
    seriesLayoutBy: 'row'
  }
});

Поздравляю, молодец!