Преобразование выборки или плотности на основе области масштабирования

У меня есть большой набор данных временных рядов, который при уменьшении масштаба позволяет просматривать интерактивный график. Кто-нибудь экспериментировал с динамическим уменьшением размера набора данных в зависимости от уровня масштабирования? Например, преобразование выборки, при котором номер выборки применяется к видимым данным, а не ко всему набору данных, но затем отключается за пределами определенного размера домена. Возможно ли такое?

Вот макет:

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

dt2 = datetime.datetime.now()
ydt = datetime.timedelta(days=365)
dt1 = dt2 - ydt
dt1 = dt1.timestamp()
dt2 = dt2.timestamp()
times = [random.uniform(dt1, dt2) for i in range(10**5)]
times.sort()
values = []
for t in times:
    d = {}
    t = datetime.datetime.fromtimestamp(t)
    t = t.isoformat(" ", timespec = "seconds")
    v = random.uniform(0, 1000)
    c = random.randint(0,1)
    d["time"] = t
    d["data"] = v
    d["category"] = c
    values.append(d)

with open("./test.json", "wt") as f:
    json.dump(values[:10**4], f)

И вот чего мне удалось добиться в редакторе Vega (пришлось обрезать данные, чтобы они соответствовали ссылке).

Это решено?

davidebacci 01.09.2024 11:06

Я попробую ответить на этот вопрос после того, как закончу решение моего предыдущего вопроса.

user19087 01.09.2024 18:01
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сигналы официально не поддерживаются в VL, но их можно взломать. Здесь рассчитывается диапазон домена и в зависимости от значения делается выборка. Очевидно, вы можете расширить троичный оператор дополнительными условиями или придумать выражение для своей логики.

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      {"time": "2023-08-31 15:12:40", "data": 265.1037232391961, "category": 1},
      {"time": "2023-08-31 15:15:26", "data": 989.2391954577464, "category": 1},
      {"time": "2023-08-31 15:15:29", "data": 426.3748533977788, "category": 0},
      {"time": "2023-08-31 15:18:11", "data": 563.7725296786067, "category": 1},
      {"time": "2023-08-31 15:21:25", "data": 322.4493083566362, "category": 0},
      {"time": "2023-08-31 15:24:54", "data": 822.6771646740021, "category": 1},
      {
        "time": "2023-08-31 15:28:10",
        "data": 294.37404484299054,
        "category": 1
      },
      {"time": "2023-08-31 15:28:22", "data": 838.7462086185608, "category": 0},
      {"time": "2023-08-31 15:35:58", "data": 961.3893188770259, "category": 0},
      {
        "time": "2023-08-31 15:36:07",
        "data": 241.45631836625802,
        "category": 0
      },
      {
        "time": "2023-08-31 15:49:33",
        "data": 191.96326506124362,
        "category": 0
      },
      {
        "time": "2023-08-31 15:51:15",
        "data": 450.50733664623965,
        "category": 1
      },
      {"time": "2023-08-31 15:56:35", "data": 390.5921971631632, "category": 1},
      {"time": "2023-08-31 15:57:52", "data": 829.8364876130439, "category": 1},
      {"time": "2023-08-31 16:01:06", "data": 996.0349700996576, "category": 0},
      {"time": "2023-08-31 16:02:36", "data": 78.24722444300802, "category": 0},
      {"time": "2023-08-31 16:14:05", "data": 942.3350040849994, "category": 0},
      {"time": "2023-08-31 16:14:56", "data": 860.58714895142, "category": 1},
      {"time": "2023-08-31 16:15:08", "data": 515.199102407516, "category": 1},
      {
        "time": "2023-08-31 16:23:20",
        "data": 166.05721829849873,
        "category": 1
      },
      {
        "time": "2023-08-31 16:30:05",
        "data": 439.73137493646266,
        "category": 0
      },
      {"time": "2023-08-31 16:32:31", "data": 869.245076742056, "category": 0},
      {
        "time": "2023-08-31 16:35:48",
        "data": 480.50968063008304,
        "category": 1
      },
      {"time": "2023-08-31 16:37:50", "data": 476.877035209344, "category": 1},
      {"time": "2023-08-31 16:39:36", "data": 733.3017448826324, "category": 0},
      {"time": "2023-08-31 16:44:17", "data": 636.686519092496, "category": 1},
      {"time": "2023-08-31 16:45:08", "data": 694.5261775005811, "category": 0},
      {"time": "2023-08-31 16:51:36", "data": 695.7401884245502, "category": 0},
      {"time": "2023-08-31 16:55:29", "data": 570.0935946720598, "category": 1},
      {
        "time": "2023-08-31 16:57:05",
        "data": 277.22052647262717,
        "category": 0
      },
      {
        "time": "2023-08-31 16:58:27",
        "data": 480.36926264607274,
        "category": 1
      },
      {"time": "2023-08-31 17:02:34", "data": 893.3698570026319, "category": 1},
      {
        "time": "2023-08-31 17:05:32",
        "data": 236.71895124154685,
        "category": 1
      },
      {"time": "2023-08-31 17:08:46", "data": 573.0841835923452, "category": 0},
      {"time": "2023-08-31 17:14:37", "data": 191.7254918774728, "category": 0},
      {"time": "2023-08-31 17:16:43", "data": 94.93763899240804, "category": 1},
      {"time": "2023-08-31 17:24:40", "data": 936.4038465823089, "category": 0},
      {
        "time": "2023-08-31 17:31:09",
        "data": 390.84825100994567,
        "category": 1
      },
      {"time": "2023-08-31 17:35:35", "data": 14.48187309843274, "category": 0},
      {
        "time": "2023-08-31 17:35:47",
        "data": 443.05398617944593,
        "category": 1
      },
      {"time": "2023-08-31 17:40:44", "data": 30.0828399028229, "category": 0},
      {"time": "2023-08-31 17:48:33", "data": 768.0549896500464, "category": 1},
      {"time": "2023-08-31 17:53:29", "data": 71.57068127924227, "category": 0},
      {"time": "2023-08-31 18:04:56", "data": 594.7138236213322, "category": 0},
      {"time": "2023-08-31 18:06:44", "data": 29.21370270526036, "category": 0},
      {"time": "2023-08-31 18:28:22", "data": 852.7093808483378, "category": 1},
      {"time": "2023-08-31 18:30:01", "data": 576.9728506525139, "category": 1},
      {"time": "2023-08-31 18:31:41", "data": 968.1882202042807, "category": 1},
      {"time": "2023-08-31 18:31:51", "data": 185.6873327854428, "category": 1},
      {"time": "2023-08-31 18:33:31", "data": 258.211113709635, "category": 0},
      {"time": "2023-08-31 18:36:36", "data": 641.264570256715, "category": 1},
      {"time": "2023-08-31 18:39:52", "data": 717.6143367808544, "category": 1},
      {"time": "2023-08-31 18:39:52", "data": 191.4611806426172, "category": 1},
      {"time": "2023-08-31 18:41:38", "data": 136.9116350629923, "category": 0},
      {"time": "2023-08-31 18:57:48", "data": 62.11343548023751, "category": 1},
      {"time": "2023-08-31 18:58:26", "data": 529.5089127094398, "category": 0},
      {
        "time": "2023-08-31 19:07:54",
        "data": 153.13269404700824,
        "category": 1
      },
      {"time": "2023-08-31 19:09:17", "data": 705.4049459845114, "category": 0},
      {
        "time": "2023-08-31 19:11:07",
        "data": 300.90132125121005,
        "category": 1
      },
      {"time": "2023-08-31 19:20:25", "data": 946.4725291504993, "category": 1},
      {
        "time": "2023-08-31 19:23:48",
        "data": 319.04133613813724,
        "category": 1
      },
      {"time": "2023-08-31 19:24:25", "data": 464.2923297748929, "category": 1},
      {"time": "2023-08-31 19:28:02", "data": 836.436678063193, "category": 1},
      {"time": "2023-08-31 19:28:08", "data": 5.992853044164859, "category": 1},
      {"time": "2023-08-31 19:40:01", "data": 873.6847072580948, "category": 1},
      {"time": "2023-08-31 19:43:41", "data": 431.0286183407737, "category": 1},
      {
        "time": "2023-08-31 19:51:22",
        "data": 396.43260404732825,
        "category": 0
      },
      {"time": "2023-08-31 19:54:08", "data": 575.9715221353141, "category": 0},
      {
        "time": "2023-08-31 19:55:53",
        "data": 44.016217670442614,
        "category": 0
      },
      {"time": "2023-08-31 19:58:14", "data": 988.9639046666363, "category": 1},
      {"time": "2023-08-31 20:05:53", "data": 742.2798696276691, "category": 0},
      {"time": "2023-08-31 20:07:13", "data": 982.7119961613008, "category": 0},
      {"time": "2023-08-31 20:15:20", "data": 976.3381077100345, "category": 1},
      {"time": "2023-08-31 20:20:15", "data": 498.5276910780252, "category": 0},
      {"time": "2023-08-31 20:22:29", "data": 301.4863894174468, "category": 1},
      {
        "time": "2023-08-31 20:31:03",
        "data": 232.56452406666895,
        "category": 1
      },
      {"time": "2023-08-31 20:33:52", "data": 694.171014904713, "category": 1},
      {
        "time": "2023-08-31 20:35:45",
        "data": 102.79567934930212,
        "category": 1
      },
      {
        "time": "2023-08-31 20:47:32",
        "data": 431.64822699883376,
        "category": 1
      },
      {"time": "2023-08-31 20:55:19", "data": 683.217576875891, "category": 0},
      {"time": "2023-08-31 20:55:36", "data": 879.5945045918183, "category": 1},
      {"time": "2023-08-31 21:04:28", "data": 164.6834561802648, "category": 1},
      {
        "time": "2023-08-31 21:06:04",
        "data": 22.588620229922583,
        "category": 1
      },
      {"time": "2023-08-31 21:07:10", "data": 757.0796861192514, "category": 1},
      {"time": "2023-08-31 21:23:43", "data": 848.456892794343, "category": 1},
      {
        "time": "2023-08-31 21:34:38",
        "data": 447.89147371830785,
        "category": 1
      },
      {"time": "2023-08-31 21:45:30", "data": 862.3116375036777, "category": 1},
      {"time": "2023-08-31 21:47:00", "data": 967.0312319533795, "category": 0},
      {"time": "2023-08-31 21:47:56", "data": 966.4938018703745, "category": 1},
      {"time": "2023-08-31 21:49:45", "data": 890.2567189914545, "category": 0},
      {
        "time": "2023-08-31 21:55:40",
        "data": 362.80312104639677,
        "category": 1
      },
      {"time": "2023-08-31 21:58:55", "data": 834.7469369912607, "category": 1},
      {"time": "2023-08-31 22:01:02", "data": 584.1447613550432, "category": 1},
      {"time": "2023-08-31 22:01:06", "data": 82.66592460479994, "category": 1},
      {
        "time": "2023-08-31 22:02:00",
        "data": 332.67959271479384,
        "category": 0
      },
      {
        "time": "2023-08-31 22:02:32",
        "data": 316.51081491367347,
        "category": 0
      },
      {
        "time": "2023-08-31 22:08:31",
        "data": 336.10098602094985,
        "category": 1
      },
      {"time": "2023-08-31 22:18:52", "data": 873.7313013506864, "category": 0},
      {
        "time": "2023-08-31 22:19:24",
        "data": 312.42947148514776,
        "category": 1
      },
      {"time": "2023-08-31 22:28:48", "data": 582.8096654568776, "category": 1}
    ]
  },
  "params": [{"name": "test", "expr": "span(grid_time)/100000"}],
  "transform": [
    {"filter": "datum.data > 0"},
    {"sample": {"signal": "test<130?100:10"}}
  ],
  "title": "Too Much Data",
  "config": {"font": "monospace"},
  "width": "container",
  "layer": [
    {
      "params": [
        {
          "name": "grid",
          "bind": "scales",
          "select": {
            "type": "interval",
            "encodings": ["x"],
            "on": "[mousedown[!event.shiftKey], mouseup] > mousemove",
            "translate": "[mousedown[!event.shiftKey], mouseup] > mousemove!"
          }
        },
        {
          "name": "brush",
          "select": {
            "type": "interval",
            "encodings": ["x"],
            "on": "[mousedown[event.shiftKey], mouseup] > mousemove",
            "translate": "[mousedown[event.shiftKey], mouseup] > mousemove!"
          }
        }
      ],
      "mark": "point",
      "encoding": {
        "x": {"field": "time", "type": "temporal"},
        "y": {"field": "data", "type": "quantitative"},
        "color": {"field": "category", "type": "nominal"}
      }
    },
    {
      "transform": [
        {"filter": {"param": "brush"}},
        {"aggregate": [{"op": "count", "as": "count"}]}
      ],
      "mark": "text",
      "encoding": {"text": {"field": "count", "type": "quantitative"}}
    }
  ]
}

Хм, я подумывал о добавлении обработчика сигнала grid_time JS и ручном удалении данных с помощью наборов изменений, но это намного проще, спасибо! Мне больше не нужно беспокоиться о том, безопасно ли изменять данные в обработчике и безопасно ли вызывать runAsync или как это сделать insert, сохраняя порядок. Только время покажет, достаточно ли преобразования sample для сохранения формы моих данных, или мне нужен более сложный алгоритм прореживания кривой в JS.

user19087 31.08.2024 02:32

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

user19087 31.08.2024 02:34

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

davidebacci 31.08.2024 09:30

Не нужно еще одного вопроса, я все понял. test можно визуализировать на графике и в консоли как ... text: {expr: "warn(test)"} ..., в отличие от записей данных, которые доступны в datum или data('name') для конкретных источников.

user19087 01.09.2024 18:45

У меня есть эвристика, которая в среднем отображает около X баллов: total_count_orig / (grid_count_orig / X). Источник данных orig предварительно отсортирован, поэтому я использую эффективный двоичный поиск. Приятно видеть, как точки появляются и исчезают при масштабировании, но, к сожалению, при дальнейшем увеличении производительность становится несостоятельной. С X=400 и никогда не достигающим пика выше 425 (мои данные довольно регулярны), он быстро замедляется до ползания, даже когда я настолько увеличен, видно только 10-20 точек данных.

user19087 02.09.2024 10:47

Как только я уменьшаю масштаб, производительность восстанавливается. Я подозреваю, что sample выполняет повторную выборку с нуля всякий раз, когда меняется сигнал сетки/представления, и он становится очень медленным, когда ему приходится отфильтровывать почти все данные. Пожалуйста, дайте мне знать, если есть более эффективный подход!

user19087 02.09.2024 10:48

VegaLite не предназначен для обработки огромного количества отдельных точек данных — данные обычно необходимо каким-то образом агрегировать перед их визуализацией. Вероятно, вам нужно посмотреть что-то вроде github.com/vega/vega-plus, которое может обрабатывать миллионы записей.

davidebacci 02.09.2024 10:53

Как и в этом вопросе, мои данные довольно просты — кодировки x (время), y и color. Он уже предварительно отфильтрован, поэтому я не использую никаких преобразований. Это заставляет меня думать, что такой проект, как VegaFusion, мне не поможет, но VegaPlus может быть излишним. Знаете ли вы какие-либо проекты Vega, которые могут осуществлять потоковую передачу из базы данных sqlite?

user19087 02.09.2024 11:19

Я собираю данные за большой период времени, поэтому имеется около 50 000 строк (и я хочу объединить еще два графика), но я использую только простые метки в виде точек. Несмотря на 50 000 строк, меня интересует только отрисовка примерно 500 отметок за раз. Настоящая главная проблема это sample. Это смехотворно медленно и перемешивает мои данные. Как вы думаете, стоит ли попробовать заменить его на filter. Я бы создал ячейки X и назначил каждой строке ячейку. Когда срабатывает сигнал представления/сетки, я бы вычислял текущий уровень масштабирования (из X) и отфильтровывал все строки >= x.

user19087 02.09.2024 11:20

50 тысяч все еще довольно много, но да, я бы пошел по пути фильтра. Проблема в том, что при полном уменьшении масштаба вам также потребуется выполнить группировку, поскольку 50 тысяч точек, вероятно, слишком много для одновременного отображения. Отметьте этот вопрос как решенный и задайте новый вместе с попыткой, если вы все еще испытываете трудности.

davidebacci 02.09.2024 11:24

У фильтра та же проблема: чем больше вы увеличиваете масштаб, тем медленнее становится VegaLite, даже если вы только панорамируете и панорамируете только 5-10 знаков. И, как sample, он меняет порядок моих данных, хотя, по крайней мере, каждый отдельный контейнер остается отсортированным при повторном введении, что должно хорошо работать с Chrome timsort.

user19087 02.09.2024 16:29

Интересно.... Если вы сначала отфильтруете {param: grid}, график при увеличении станет намного более отзывчивым. Очевидно, фильтруется весь набор данных, даже записи, находящиеся вне поля зрения, но фильтрация по предикату выбора оптимизирована гораздо лучше, поэтому последующим фильтрам нужно фильтровать только видимые данные.

user19087 02.09.2024 16:36

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

user19087 02.09.2024 16:57

Я просмотрел исходный код образца и считаю, что смогу улучшить его производительность для своего использования, хотя не уверен, что достаточно ли этого. Взгляните на VegaFusion или VegaPlus: это движки, которые переносят сложные вычисления на отдельный процессор базы данных. У меня их нет, поэтому я не уверен, что они отвечают моим потребностям. Конечно, потоковая передача данных будет вести себя как тот сэмплер, который мне нужен, но я не уверен, что оно того стоит. Как вы думаете, для моего конкретного использования мне следует сосредоточиться на специальном сэмплере или стороннем проекте Vega?

user19087 02.09.2024 18:42

В любом случае, если вы знаете, как создать собственный vega.transform в vega-lite, я буду признателен.

user19087 02.09.2024 18:43

Можете ли вы задать новый вопрос с полной рабочей спецификацией и всеми загруженными 50 тысячами точек данных. Возможно, вы сможете фильтровать и выполнять выборку, используя существующие преобразования, но тестирование невозможно без данных и спецификации. VL более ограничен, и с Vega у вас может быть больше возможностей.

davidebacci 02.09.2024 19:06

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

davidebacci 02.09.2024 19:07

Другие вопросы по теме