Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - VBA

Страница: 1 |

 

  Вопрос: Помогите ускорить процесс создания диаграммы EXCEL Добавлено: 15.08.07 18:27  

Автор вопроса:  Vilor
Задача: построение графика исходя из данных, полуенных из базы данных. Необходимо на диаграмме создать порядка 120-190 рядов (кажый ряд прямая построенная по 2-м точкам), и отформатировать (всего около 20 видов форматирования).
Путь решения: на лист Data переношу в столбец A дату-время, в столбец B - значение каждая нечетная строка - начало ряда, следующая за ней четная - вторя точка ряда.
Ряды создаю следующим образом:
Set nCh = Workbooks(ThisWorkbook.Name).Charts("Grafic")
  With nCh
    .PlotVisibleOnly = True
    .Deselect
    iX = 0
    For iR = 1 To maxRows - 1 Step 2
        iX = iX + 1
        iiU = vArrIndex(iX, 1)
        iiS = vArrIndex(iX, 2)
        If iiU = 0 Or iiS = 0 Then Exit For
        Set nS = .SeriesCollection.NewSeries
       'nCh.SetSourceData Source:=Sheets("Data").Range("A" & VBA.CStr(iR) & ":B" & VBA.CStr(iR + 1)), _
            PlotBy:=xlColumns
           'Set nS = .SeriesCollection(1)
        With nS
            .XValues = "=Data!R" & iR & "C1:R" & iR + 1 & "C1"
            .Values = "=Data!R" & iR & "C2:R" & iR + 1 & "C2"
            .Name = iiU & "/" & iiS & " - " & vUnits(iiU).UnitName & " " & vUnits(iiU).UnitStats(iiS).StateName '& " " & VBA.Format(.XValues(1), "HH:MM:SS") '"=Data!R" & iRowHome & "C1:R" & iRowHome & "C2"
            .Shadow = False
            If vUnits(iiU).UnitStats(iiS).StateMarkerType <> 0 Then
                .MarkerBackgroundColorIndex = xlNone
                .MarkerForegroundColorIndex = vUnits(iiU).UnitStats(iiS).StateMarkerColor
                .MarkerStyle = vUnits(iiU).UnitStats(iiS).StateMarkerType '.MarkerStyle = xlNone
                .MarkerSize = IIf(vUnits(iiU).UnitStats(iiS).StateMarkerSize >= 2, vUnits(iiU).UnitStats(iiS).StateMarkerSize, 2)
                Else
                .MarkerBackgroundColorIndex = xlNone
                .MarkerBackgroundColorIndex = xlNone
                .MarkerStyle = xlNone
                End If
            With .Border
                .Color = vUnits(iiU).UnitStats(iiS).StateColor
                .LineStyle = vUnits(iiU).UnitStats(iiS).StateLineType '''.LineStyle = xlDash
                .Weight = xlMedium
            End With
        End With
    Next iR
  .Refresh
  .Select
  end with

Проблема: когда рядов 10-20 еще ничего, а если их чило более 100, то на их создание и форматирование (в основном на присвоение значения .XValues и .Values уходит 6-7 минут на прличном компе.
Стндартые методы ускорения работы типа:
    Application.ScreenUpdating = False
    Application.EnableAnimations = False
    Application.EnableEvents = False
    Application.ShowChartTipNames = False
    Application.Interactive = False
не очень-то помогают.
Пытался .XValues и .Values присваивать не значениям ячейки листа дата, а значениям в массиве - те же грабли.

Пожалуста, П О М О Г И Т Е оптимизировать код построения диаграммы. По идее она должна быть еще и интерактивной, а на её построение уходит времени больше, чем есть терпение у пользователей.
Заранее благодарен всем ответившим...

Ответить

  Ответы Всего ответов: 12  

Номер ответа: 1
Автор ответа:
 GenyaA



Вопросов: 0
Ответов: 185
 Web-сайт: www.genyaa.nm.ru
 Профиль | | #1
Добавлено: 15.08.07 23:15
Может нужно попробовать изменить подход к построению?... (правда я мог неверно понять суть и смысл данных исходной таблицы)...

Но может быть можно привести исходную таблицу к виду:

    A     |   B  |  C
Дата-Время|Начало|Конец
..


вместо последовательных данных - четная-начало, нечетная-конец.

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

Как именно у Вас реализованно форматирование рядов - я не стал разбираться в этом (довольно сложно вникнуть в чужой код).. Но я использовал часть макроса, полученного из автозаписи макросов, в цикле, и перебор 250 рядов и форматирование их (изменяя цвет и толщину линии) заняло у меня около 5 сек без выключенного ScreenUpdating.

Ответить

Номер ответа: 2
Автор ответа:
 GenyaA



Вопросов: 0
Ответов: 185
 Web-сайт: www.genyaa.nm.ru
 Профиль | | #2
Добавлено: 15.08.07 23:18
А забыл сказать... Наверно это важно... я строил график (диаграмму - Chart, ChartType = xlLine):

    Charts.Add
    ActiveChart.ChartType = xlLine
    ActiveChart.SetSourceData Source:=Sheets("Лист1";).Range("A1:C250";), PlotBy _
        :=xlRows
    ActiveChart.Location Where:=xlLocationAsNewSheet

Ответить

Номер ответа: 3
Автор ответа:
 Vilor



Вопросов: 5
Ответов: 28
 Профиль | | #3 Добавлено: 16.08.07 12:50
1. Проблема не в скорости форматирования графического представления рядов (цвет, маркер, тип линии), а именно в скорости присвоения значений XValue и Value объекта Series. Для каждого ряда время присвоения значений XValue и Value примерно 2 секунды (!!! просто УЖАС).
Есть варианты решения проблемы?

2. Может быть можно ограничить точность (погрешность) прочерчивания линий?
3. Или диаграмму с данными располагать на одном листе?

4. Не могу понять к какому виду еще можно привести исходную таблицу. Диаграмма линейная, предназначена для представления в графической форме режимов работы оборудования, где каждый ряд - определенный режим, имеющий свой цвет, маркер, тип линии. Начало/конец ряда по шкале дата/время это соотв. время начала/окончания режима. Высота точек начала и окончания ряда это сумма необходимой высоты строки в диаграмме (определенной для каждой единицы оборудования) + относительная высота (определеяемая собствено режимом работы, если необходимо вычертить наклонную линию).
Как мне кажется исходные данные в форме:
A | B | C
Дата-Время|Начало|Конец

не смогут обеспечить решение задачи.

P.S. Спасибо за участие,
надеюсь на Вашу помошь в дальнейшем решении проблемы

Ответить

Номер ответа: 4
Автор ответа:
 Vilor



Вопросов: 5
Ответов: 28
 Профиль | | #4 Добавлено: 16.08.07 12:56
Еще один вопрос:
Может быть попробовать располагать исходные данные в форме:

   A \ B \ C \ D \
   ДТ1 \ V1 \ ДТ2 \ V2 \
]
где:
ДТ1- дата/время начала ряда
V1 - высота начала;
ДТ2- дата/время окончания;
V2 - высота окончания.
??????????????????????????????????????????

Ответить

Номер ответа: 5
Автор ответа:
 GenyaA



Вопросов: 0
Ответов: 185
 Web-сайт: www.genyaa.nm.ru
 Профиль | | #5
Добавлено: 16.08.07 13:48
Чего-то я торможу... а можно показать, как именно выглядит Ваш график... вместе с исходными данными... например, на примере трех-пяти линий? (У меня чего-то воображения не хватает, чтобы понять, что требуется в графике.)

Ответить

Номер ответа: 6
Автор ответа:
 Vilor



Вопросов: 5
Ответов: 28
 Профиль | | #6 Добавлено: 17.08.07 00:07
Как показать? Напиши e-mail - выщлю screen и/или исходник.
А в символьном виде примерно так:
ЗАДАЧА:
                    _______ ___
Оборудование1 | / \ _____ __ / \
              |
Оборудование2 | ____ ____ __
              | _______
Оборудование3 | / \ _____ _
              |
Оборудование4 | __________________ _____
              ....................................
              08:00 12:00 20:00
Каждый из несоприкасаюзихся друг с другом отрезков может быть своего цвета, иметь уникальный маркер и тип/толщину линии.
Каждый из отрезков (даже соприкасающихся) - отдельный режим работы оборудования.
----------------------------------------

ИСХОДНЫЕ ДАННЫЕ:
Исходные данные о старте-стопе режимов хранятся в mdb в Таблице1 формата:
Id_Оборудования / Id_Режима / ВремяСтарта
--------------------------------------------
Данные о режимах в Таблице2:
Id_Режима / Наименование / Тип линии / Цвет линии / Толщина_линии / Относительная_высота_начала / Относительная_высота_конца / и т.д.
--------------------------------------------
Исходные данные об оборудовании (Таблица3):
Id_Оборудования / Наименование / Номер_строки(ВысотаПоОсиY) / и т.д.
--------------------------------------------

ОПИСАНИЕ ОБРОАБОТКИ ИСХОДНЫХ ДАННЫХ:

Координаты начала каждого отрезка:
X = ВремяСтарта режима из таблицы1
Y = Номер_строки * 10 + Относительная_высота_начала из таблицы2

Координаты конца каждого отрезка:
X = ВремяСтарта следующего режима из таблицы1 для оборудования с этим же ID (или режима с ID=0)
Y = Номер_строки * 10 + Относительная_высота_конца из таблицы2

Форматируется ряд диаграммы (отрезок) исходя из данных Таблицы3 для Id_Режима
из обрабатываемой записи в Таблице1.

Надеюсь теперь немного понятнее стало?
Планировал рисовать синусоиды от точки начала до точки окончания, но раз такие тормоза - не до излишеств... :-(

С нетерпением буду ожидать предложений.
P.S. В твоем примере:
ActiveChart.SetSourceData Source:=Sheets("Лист1";).Range("A1:C250";), PlotBy _
        :=xlRows
SetSourceData работает действительно очень быстро, но он создает один ряд, в котором все точки соединены и форматируется (цвет, толщина и тип линий, а также маркеры) весь ряд целиком. Мне же необходимо, чтобы каждый отрезок имел свой цвет.

Можно, конечно создать 120-200 диаграмм (наверное), но муторно это и как-то нерационально. Пытался создать несколько SeriesCollection для одной диаграммы (типа однотипные ряды в одну коллекцию и форматировать сразу их все) - не получилось.

Ответить

Номер ответа: 7
Автор ответа:
 Vilor



Вопросов: 5
Ответов: 28
 Профиль | | #7 Добавлено: 17.08.07 00:12
Блин! Движок форума "сожрал" пробелы (их везде разное количество) в эскизе диаграммы - не слишком наглядно.
Напиши e-mail - вышлю рисунок.
Попробую так:

                    _______                ___
Оборудование1 |    /       \   _____   __ /   \
              |
Оборудование2 |            ____    ____  __  
              |              _______
Оборудование3 |             /       \   _____  _
              |
Оборудование4 |    __________________      _____
              ....................................
              08:00               12:00          20:00

Ответить

Номер ответа: 8
Автор ответа:
 Vilor



Вопросов: 5
Ответов: 28
 Профиль | | #8 Добавлено: 17.08.07 00:24
Если исходную таблицу я приведу к формату:

  A \ B \ C \ D \ E
ID_Режима \ ДТ1 \ V1 \ ДТ2 \ V2
Empty \ empty\Empty\Empty\Empty
ID_Режима \ ДТ1 \ V1 \ ДТ2 \ V2


и использую
ActiveChart.SetSourceData Source:=Sheets("Лист1";).Range("B1:E250";), PlotBy _
        :=xlRows
ио у меня будет несколько рядов или один?

Ответить

Номер ответа: 9
Автор ответа:
 GenyaA



Вопросов: 0
Ответов: 185
 Web-сайт: www.genyaa.nm.ru
 Профиль | | #9
Добавлено: 17.08.07 12:18
Ок. теперь понятно.

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

Думаю это не должно стать большой проблемой построить график по 2-м осям из таблицы с шагом по времени (с допустимой точностью) по срокам, и с ID процессов по столбцам. Построение же должно быть именно Charts.Add сразу по всей таблице. (Именно дабавление рядов в график занимает кучу времени.)

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

Перебор рядов для переформатирования не должно будет занять слишком много времени.

Ответить

Номер ответа: 10
Автор ответа:
 Vilor



Вопросов: 5
Ответов: 28
 Профиль | | #10 Добавлено: 17.08.07 20:09
1. "... сшагом по времени (с допустимой точностью) по времени...." - немного недопонял о чем это и как можно установить точность построения (если можно покажи на конкретном примере кода)?

2. "Именно дабавление рядов в график занимает кучу времени" - поправлю добавление ряда происходит очень быстро, а вот присвоение значения Value и XValue - ОЧЕНЬ медленно....

2. Как после использования Charts.Add и построения сразу всей диаграммы по одной таблице я узнаю к какому режиму относиться каждый отрезок, чтобы его отформатировать? Нужно будет записывать дополнительно на лист данных Id режима и определять адрес источника данных для точки (если это возможо для точки или ряда при построение методом c помощью Source...), относительно которого определять этот самый Id режим? Может примерчиком поможешь?

3. Не очень хочется переделывать всю работу заново. Может быть есть способ ускорить присвоение значения точкам рядов с помощью свойств Value и XValue?

Ответить

Номер ответа: 11
Автор ответа:
 GenyaA



Вопросов: 0
Ответов: 185
 Web-сайт: www.genyaa.nm.ru
 Профиль | | #11
Добавлено: 17.08.07 22:15
1. "С шагом" - даже это можно обойти.. можно просто установить параметр "Шкала времени" для оси Х.

2. Возможно. Вы лучше знаете.

3. Ответил письмом по e-mail.

4. Это Ваша свобода выбора.

Ответить

Номер ответа: 12
Автор ответа:
 Vilor



Вопросов: 5
Ответов: 28
 Профиль | | #12 Добавлено: 18.08.07 16:24
Спасибо за помощь. Теперь немного надо подумать и поработать. Жаль не очень много времени есть на это. :-(
Особая благодарность за пример, отправленный по e-mail.

Еще одно предположение родилось или скорее вопрос:
Возможно очень медленной присвоение значений XValue и Value происходит из-за того, что точки попадают в невидимую в текущем представлении диаграммы область? Дело в том, что при задании мин. и макс. значений шкале времени т.о.:
ActiveChart.Axes(xlCategory)
      .MinimumScale = DT1
      .MaximumScale = DT2
, (где DT1 и DT2 - переемнные в формате Data) если еще не построено ни одного ряда, то происходит ошибка выполнения. Пэтому я сначала строю все ряды, а затем форматирую диаграмму. Может в этом кроется ошибка? Почему ельзя привоить MinimumScale и MaximumScale, до построения рядов?
      

Ответить

Страница: 1 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам