По какой-то причине мне нужно передать длинный массив из 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' } });
Поздравляю, молодец!