Задача: построение графика исходя из данных, полуенных из базы данных. Необходимо на диаграмме создать порядка 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 присваивать не значениям ячейки листа дата, а значениям в массиве - те же грабли.
Пожалуста, П О М О Г И Т Е оптимизировать код построения диаграммы. По идее она должна быть еще и интерактивной, а на её построение уходит времени больше, чем есть терпение у пользователей.
Заранее благодарен всем ответившим...
Может нужно попробовать изменить подход к построению?... (правда я мог неверно понять суть и смысл данных исходной таблицы)...
Но может быть можно привести исходную таблицу к виду:
A | B | C
Дата-Время|Начало|Конец
..
вместо последовательных данных - четная-начало, нечетная-конец.
Тогда построение самого графика займет меньше секунды, даже если количество рядов будет 250.
Как именно у Вас реализованно форматирование рядов - я не стал разбираться в этом (довольно сложно вникнуть в чужой код).. Но я использовал часть макроса, полученного из автозаписи макросов, в цикле, и перебор 250 рядов и форматирование их (изменяя цвет и толщину линии) заняло у меня около 5 сек без выключенного ScreenUpdating.
1. Проблема не в скорости форматирования графического представления рядов (цвет, маркер, тип линии), а именно в скорости присвоения значений XValue и Value объекта Series. Для каждого ряда время присвоения значений XValue и Value примерно 2 секунды (!!! просто УЖАС).
Есть варианты решения проблемы?
2. Может быть можно ограничить точность (погрешность) прочерчивания линий?
3. Или диаграмму с данными располагать на одном листе?
4. Не могу понять к какому виду еще можно привести исходную таблицу. Диаграмма линейная, предназначена для представления в графической форме режимов работы оборудования, где каждый ряд - определенный режим, имеющий свой цвет, маркер, тип линии. Начало/конец ряда по шкале дата/время это соотв. время начала/окончания режима. Высота точек начала и окончания ряда это сумма необходимой высоты строки в диаграмме (определенной для каждой единицы оборудования) + относительная высота (определеяемая собствено режимом работы, если необходимо вычертить наклонную линию).
Как мне кажется исходные данные в форме:
A | B | C
Дата-Время|Начало|Конец
не смогут обеспечить решение задачи.
P.S. Спасибо за участие,
надеюсь на Вашу помошь в дальнейшем решении проблемы
Чего-то я торможу... а можно показать, как именно выглядит Ваш график... вместе с исходными данными... например, на примере трех-пяти линий? (У меня чего-то воображения не хватает, чтобы понять, что требуется в графике.)
Как показать? Напиши 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. В твоем примере:
SetSourceData работает действительно очень быстро, но он создает один ряд, в котором все точки соединены и форматируется (цвет, толщина и тип линий, а также маркеры) весь ряд целиком. Мне же необходимо, чтобы каждый отрезок имел свой цвет.
Можно, конечно создать 120-200 диаграмм (наверное), но муторно это и как-то нерационально. Пытался создать несколько SeriesCollection для одной диаграммы (типа однотипные ряды в одну коллекцию и форматировать сразу их все) - не получилось.
Судя по всему этому, теперь я точно уверен, что решение ускорения лежит именно в изменении структуры представления исходных данных для построения графика (диаграммы).
Думаю это не должно стать большой проблемой построить график по 2-м осям из таблицы с шагом по времени (с допустимой точностью) по срокам, и с ID процессов по столбцам. Построение же должно быть именно Charts.Add сразу по всей таблице. (Именно дабавление рядов в график занимает кучу времени.)
В данных же таблицы проставить значения (апроксимированные на момент времени шага таблицы по линейным или нужным закономерностям), если процесс идет. Если же процесс в этот момент времени шага таблицы не идет, то поле данных должно быть пустым (именно пустым, даже без формулы, возвращающей пустую строку).
Перебор рядов для переформатирования не должно будет занять слишком много времени.
1. "... сшагом по времени (с допустимой точностью) по времени...." - немного недопонял о чем это и как можно установить точность построения (если можно покажи на конкретном примере кода)?
2. "Именно дабавление рядов в график занимает кучу времени" - поправлю добавление ряда происходит очень быстро, а вот присвоение значения Value и XValue - ОЧЕНЬ медленно....
2. Как после использования Charts.Add и построения сразу всей диаграммы по одной таблице я узнаю к какому режиму относиться каждый отрезок, чтобы его отформатировать? Нужно будет записывать дополнительно на лист данных Id режима и определять адрес источника данных для точки (если это возможо для точки или ряда при построение методом c помощью Source...), относительно которого определять этот самый Id режим? Может примерчиком поможешь?
3. Не очень хочется переделывать всю работу заново. Может быть есть способ ускорить присвоение значения точкам рядов с помощью свойств Value и XValue?
Спасибо за помощь. Теперь немного надо подумать и поработать. Жаль не очень много времени есть на это.
Особая благодарность за пример, отправленный по e-mail.
Еще одно предположение родилось или скорее вопрос:
Возможно очень медленной присвоение значений XValue и Value происходит из-за того, что точки попадают в невидимую в текущем представлении диаграммы область? Дело в том, что при задании мин. и макс. значений шкале времени т.о.:
, (где DT1 и DT2 - переемнные в формате Data) если еще не построено ни одного ряда, то происходит ошибка выполнения. Пэтому я сначала строю все ряды, а затем форматирую диаграмму. Может в этом кроется ошибка? Почему ельзя привоить MinimumScale и MaximumScale, до построения рядов?