Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Visual Basic: Общие вопросы > Ускорение отрисовки графика


Автор: Penumbra 22.09.16, 20:14
[attach=#0][/attach]Доброго времени суток
Я строю график по данным из БД.
в БД сохранены 222200 записей ( напряжение с шагом 2 секунды)
если я строю график за промежуток в пару часов график прорисовывается довольно быстро, но если я запрашиваю данные за период в 5-6 суток то график строится 2-3 минуты! :!:
может можно как-то увеличить скорость построения графика?
файл

Автор: Akina 22.09.16, 20:42
Цитата Penumbra @
может можно как-то увеличить скорость построения графика?

Когда ты строишь график за длительный промежуток, то в одной пиксельной колонке экрана у тебя "совмещается" несколько значений, а отрисовывается , видимо, по самому большому из них. Посему предлагаю заранее спросить контрол, сколько же нужно будет реально рисовать колонок в пикселах, и в запросе соответствующим образом сгруппировать исходные данные для отрисовки, типа
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    select ..., max(value) as value
    from ...
    where ...
    group by fix(@pixel_cols_count * (dt - @start_dt) / (@end_dt - @start_dt))

Т.е. даже на самом широком мониторе при самом диком разрешении в полноэкранном режиме тебе придётся отрисовывать только несколько (вряд ли более 4) тысяч значений.

Автор: VisualProg 23.09.16, 08:08
Цитата
график строится 2-3 минуты


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

Например, делаете выборку 60 000 записей (DataCount). Отрисовать их все - невозможно, значит, берём ширину полотна Width (они определяют число допустимых точек в графике, пускай в тестовом примере, это будет полотно шириной в 1024 пикселя), и получаем шаг, с которым будим пропускать данные:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    int step = DataCount/Width; // 60 000 / 1 024 = 58


Это число (58) показывает что из 60 000 записей визуально можно воспринять только каждую пятьдесят восьмую точку (то есть 57 точек можно отбросить). Поэтому, перебирать такие данные в цикле надо с учётом, что интересная информация лежит только в каждом 58 элементе:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    for(int i=0;i<DataCount;i+=58){ // только каждый 58 элемент!
    ...
    }


<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    For i=0 to DataCount
    ...
    i = i+57
    next i


Так отрисовка явно ускорится, даже если вы возьмёте график за год или за 2 года. Однако, если брать данные за год, надо смотреть в сторону предложения Akina, потому что в его варианте это учитывается (тоесть, не ускоряется отрисовка, а сама выборка формирует меньше данных, беря их тем же образом сразу из базы данных)

Так же, можно не отбрасывать эти 57 значений, а провести "сглаживание" и собрать из 58 значений 1 точку, а уже по этим собранным точкам составить интерполированный график.

Автор: Akina 23.09.16, 08:18
Отбрасывать нельзя. Значения в данных идут группами. Запросто вся группа может оказаться среди этих отброшенных 57 значений - итог очевиден. Сглаживание лучше... а вот какой тип сглаживания больше подходит, решать ТС.

Автор: Penumbra 23.09.16, 10:00
Akina, печально, но я не могу разобраться в Вашем запросе, тк я в sql не силен :blush:
я запрос из бд делаю:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    str = "select * From tabl1 where dat between #" & Format(dt1, "mm\/dd\/yyyy hh:mm:01") & "# and #" & Format(dt2, "mm\/dd\/yyyy hh:mm:02") & "# order by dat ;"

Автор: Akina 23.09.16, 12:14
Penumbra
А чего там разбираться?
Вот есть у тебя N колонок пикселов. Если начальные дата-время (пусть А), и конечные (пусть В).
Ты знаешь дату-время какой-то точки (пусть Х). В какую колонку M эта точка попадёт? M = N*(Х-А)/(В-А) - чистой воды арифметика... вот для всех точек мы и считаем этот номер колонки, и по нему группируем. А из всех попавших в колонку точек берём максимальное (вот единственное, что имеет смысл обсуждать и над чем думать) значение.

Автор: Penumbra 24.09.16, 22:39
ага, вроде бы получилось!
сделал запрос
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
      rcount = dt / xx3
         str = "select cdate(avg(dat)) as dat_sr, max(param) as param_mx, min(param) as param_mn From tabl1 where dat between #" _
    & Format(dt1, "mm\/dd\/yyyy hh:mm:01") & "# and #" & Format(dt2, "mm\/dd\/yyyy hh:mm:02") & "# group by fix(cdbl(dat)/cdbl(timeserial(0,0," & rcount & ")))  ;"

вроде нормально график строит, правда точность не проверял
из значений беру максимальное и минимальное строю эти две точки сразу на графике и соединяю прямой

теперь график отрисовывается быстро, хотя сам запрос при выборке данных за 5-6 суток обрабатывается секунд 15-20

Автор: Akina 25.09.16, 13:45
Цитата Penumbra @
запрос при выборке данных за 5-6 суток обрабатывается секунд 15-20

Сделай предрасчётную укрупнёнку в отдельную таблицу. Например, минимум и максимум поминутно. На точности графика при построении за сутки или более это практически не скажется, а считать запросу куда как меньше...

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)