Код для построения графиков excel

Программное создание графика (диаграммы) в VBA Excel с помощью метода Charts.Add на основе данных из диапазона ячеек на рабочем листе. Примеры.

Метод Charts.Add

В настоящее время на сайте разработчиков описывается метод Charts.Add2, который, очевидно, заменил метод Charts.Add. Тесты показали, что Charts.Add продолжает работать в новых версиях VBA Excel, поэтому в примерах используется именно он.

Синтаксис

Charts.Add ([Before], [After], [Count])

Charts.Add2 ([Before], [After], [Count], [NewLayout])

Параметры

Параметры методов Charts.Add и Charts.Add2:

Параметр Описание
Before Имя листа, перед которым добавляется новый лист с диаграммой. Необязательный параметр.
After Имя листа, после которого добавляется новый лист с диаграммой. Необязательный параметр.
Count Количество добавляемых листов с диаграммой. Значение по умолчанию – 1. Необязательный параметр.
NewLayout Если NewLayout имеет значение True, диаграмма вставляется с использованием новых правил динамического форматирования (заголовок имеет значение «включено», а условные обозначения – только при наличии нескольких рядов). Необязательный параметр.

Если параметры Before и After опущены, новый лист с диаграммой вставляется перед активным листом.

Примеры

Таблицы

В качестве источников данных для примеров используются следующие таблицы:

Исходные таблицы для создания диаграмм

Пример 1

Программное создание объекта Chart с типом графика по умолчанию и по исходным данным из диапазона «A2:B26»:

Sub Primer1()

Dim myChart As Chart

‘создаем объект Chart с расположением нового листа по умолчанию

Set myChart = ThisWorkbook.Charts.Add

    With myChart

        ‘назначаем объекту Chart источник данных

        .SetSourceData (Sheets(«Лист1»).Range(«A2:B26»))

        ‘переносим диаграмму на «Лист1» (отдельный лист диаграммы удаляется)

        .Location xlLocationAsObject, «Лист1»

    End With

End Sub

Результат работы кода VBA Excel из первого примера:

Объект Chart с типом графика по умолчанию

Пример 2

Программное создание объекта Chart с двумя линейными графиками по исходным данным из диапазона «A2:C26»:

Sub Primer2()

Dim myChart As Chart

Set myChart = ThisWorkbook.Charts.Add

    With myChart

        .SetSourceData (Sheets(«Лист1»).Range(«A2:C26»))

        ‘задаем тип диаграммы (линейный график с маркерами)

        .ChartType = xlLineMarkers

        .Location xlLocationAsObject, «Лист1»

    End With

End Sub

Результат работы кода VBA Excel из второго примера:

Объект Chart с двумя линейными графиками (с маркерами)

Пример 3

Программное создание объекта Chart с круговой диаграммой, разделенной на сектора, по исходным данным из диапазона «E2:F7»:

Sub Primer3()

Dim myChart As Chart

Set myChart = ThisWorkbook.Charts.Add

    With myChart

        .SetSourceData (Sheets(«Лист1»).Range(«E2:F7»))

        ‘задаем тип диаграммы (пирог — круг, разделенный на сектора)

        .ChartType = xlPie

        ‘задаем стиль диаграммы (с отображением процентов)

        .ChartStyle = 261

        .Location xlLocationAsObject, «Лист1»

    End With

End Sub

Результат работы кода VBA Excel из третьего примера:

Объект Chart с круговой диаграммой

Примечание

В примерах использовались следующие методы и свойства объекта Chart:

Компонент Описание
Метод SetSourceData Задает диапазон исходных данных для диаграммы.
Метод Location Перемещает диаграмму в заданное расположение (новый лист, существующий лист, элемент управления).
Свойство ChartType Возвращает или задает тип диаграммы. Смотрите константы.
Свойство ChartStyle Возвращает или задает стиль диаграммы. Значение нужного стиля можно узнать, записав макрос.

Improve Article

Save Article

Like Article

  • Read
  • Discuss
  • Improve Article

    Save Article

    Like Article

    Prerequisite: Python | Plotting charts in excel sheet using openpyxl module | Set – 1 Openpyxl is a Python library using which one can perform multiple operations on excel files like reading, writing, arithmetic operations and plotting graphs. Charts are composed of at least one series of one or more data points. Series themselves are comprised of references to cell ranges. Let’s see how to plot Scatter, Bubble, Pie, 3D Pie Chart on an excel sheet using openpyxl. For plotting the charts on an excel sheet, firstly, create chart object of specific chart class( i.e ScatterChart, PieChart etc.). After creating chart objects, insert data in it and lastly, add that chart object in the sheet object. Let’s see how to plot different charts using realtime data. Code #1 : Plot the Bubble Chart. Bubble charts are similar to scatter charts but use a third dimension to determine the size of the bubbles. Charts can include multiple series. For plotting the bubble chart on an excel sheet, use BubbleChart class from openpyxl.chart submodule. 

    Python3

    import openpyxl

    from openpyxl.chart import BubbleChart, Reference, Series

    wb = openpyxl.Workbook()

    sheet = wb.active

    rows = [

        ("Number of Products", "Sales in USD", "Market share"),

        (14, 12200, 15),

        (20, 60000, 33),

        (18, 24400, 10),

        (22, 32000, 42),

    ]

    for row in rows:

        sheet.append(row)

    chart = BubbleChart()

    xvalues = Reference(sheet, min_col = 1,

                        min_row = 2, max_row = 5)

    yvalues = Reference(sheet, min_col = 2,

                        min_row = 2, max_row = 5)

    size = Reference(sheet, min_col = 3,

                    min_row = 2, max_row = 5)

    series = Series(values = yvalues, xvalues = xvalues,

                          zvalues = size, title ="2013")

    chart.series.append(series)

    chart.title = " BUBBLE-CHART "

    chart.x_axis.title = " X_AXIS "

    chart.y_axis.title = " Y_AXIS "

    sheet.add_chart(chart, "E2")

    wb.save("bubbleChart.xlsx")

    Output:   Code #2 : Plot the Scatter Chart Scatter, or xy charts are similar to some line charts. For plotting the Scatter chart on an excel sheet, use ScatterChart class from openpyxl.chart submodule. 

    Python3

    import openpyxl

    from openpyxl.chart import ScatterChart, Reference, Series

    wb = openpyxl.Workbook()

    sheet = wb.active

    rows = [

        ("Number of Products", "Sales in USD", "Market share"),

        (14, 12200, 15),

        (20, 60000, 33),

        (18, 24400, 10),

        (22, 32000, 42),

    ]

    for row in rows:

        sheet.append(row)

    chart = ScatterChart()

    xvalues = Reference(sheet, min_col = 1,

                        min_row = 2, max_row = 5)

    yvalues = Reference(sheet, min_col = 2,

                        min_row = 2, max_row = 5)

    size = Reference(sheet, min_col = 3,

                     min_row = 2, max_row = 5)

    series = Series(values = yvalues, xvalues = xvalues,

                          zvalues = size, title ="2013")

    chart.series.append(series)

    chart.title = " SCATTER-CHART "

    chart.x_axis.title = " X_AXIS "

    chart.y_axis.title = " Y_AXIS "

    sheet.add_chart(chart, "E2")

    wb.save(" ScatterChart.xlsx")

    Output:   Code #3 : Plot the Pie Chart Pie charts plot data as slices of a circle with each slice representing the percentage of the whole. Slices are plotted in a clockwise direction with 0° being at the top of the circle. Pie charts can only take a single series of data. For plotting the Pie chart on an excel sheet, use PieChart class from openpyxl.chart submodule. 

    Python

    import openpyxl

    from openpyxl.chart import PieChart, Reference

    wb = openpyxl.Workbook()

    sheet = wb.active

    datas = [

        ['Pie', 'Sold'],

        ['Apple', 50],

        ['Cherry', 30],

        ['Pumpkin', 10],

        ['Chocolate', 40],

    ]

    for row in datas:

        sheet.append(row)

    chart = PieChart()

    labels = Reference(sheet, min_col = 1,

                       min_row = 2, max_row = 5)

    data = Reference(sheet, min_col = 2,

                       min_row = 1, max_row = 5)

    chart.add_data(data, titles_from_data = True)

    chart.set_categories(labels)

    chart.title = " PIE-CHART "

    sheet.add_chart(chart, "E2")

    wb.save(" PieChart.xlsx")

    Output:   Code #4: Plot the Bar Chart For plotting the 3D pie chart on an excel sheet, use PieChart3D class from openpyxl.chart submodule. 

    Python3

    import openpyxl

    from openpyxl.chart import PieChart3D, Reference

    wb = openpyxl.Workbook()

    sheet = wb.active

    datas = [

        ['Pie', 'Sold'],

        ['Apple', 50],

        ['Cherry', 30],

        ['Pumpkin', 10],

        ['Chocolate', 40],

    ]

    for row in datas:

        sheet.append(row)

    chart = PieChart3D()

    labels = Reference(sheet, min_col = 1,

                       min_row = 2, max_row = 5)

    data = Reference(sheet, min_col = 2,

                       min_row = 1, max_row = 5)

    chart.add_data(data, titles_from_data = True)

    chart.set_categories(labels)

    chart.title = " 3DPIE-CHART "

    sheet.add_chart(chart, "E2")

    wb.save(" 3DPieChart.xlsx")

    Output:

    Like Article

    Save Article

    Vote for difficulty

    Current difficulty :
    Medium

    Создание диаграммы с диапазонами и фиксированное имя

    Графики могут быть созданы путем непосредственной работы с объектом Series который определяет данные диаграммы. Чтобы перейти к Series без диаграммы exisitng, вы создаете ChartObject на данном Worksheet а затем получаете объект Chart из него. Поверхность работы с объектом « Series заключается в том, что вы можете установить Values и XValues , обратившись к объектам Range . Эти свойства данных будут правильно определять Series со ссылками на эти диапазоны. Недостатком этого подхода является то, что при настройке Name не обрабатывается одно и то же преобразование; это фиксированное значение. Он не будет корректироваться с базовыми данными в исходном Range . Проверка формулы SERIES и очевидно, что имя исправлено. Это необходимо обработать, создав формулу SERIES напрямую.

    Код, используемый для создания диаграммы

    Обратите внимание, что этот код содержит объявления дополнительных переменных для Chart и Worksheet . Они могут быть опущены, если они не используются. Они могут быть полезны, однако, если вы изменяете стиль или любые другие свойства диаграммы.

    Sub CreateChartWithRangesAndFixedName()
    
        Dim xData As Range
        Dim yData As Range
        Dim serName As Range
        
        'set the ranges to get the data and y value label
        Set xData = Range("B3:B12")
        Set yData = Range("C3:C12")
        Set serName = Range("C2")
        
        'get reference to ActiveSheet
        Dim sht As Worksheet
        Set sht = ActiveSheet
        
        'create a new ChartObject at position (48, 195) with width 400 and height 300
        Dim chtObj As ChartObject
        Set chtObj = sht.ChartObjects.Add(48, 195, 400, 300)
        
        'get reference to chart object
        Dim cht As Chart
        Set cht = chtObj.Chart
        
        'create the new series
        Dim ser As Series
        Set ser = cht.SeriesCollection.NewSeries
        
        ser.Values = yData
        ser.XValues = xData
        ser.Name = serName
        
        ser.ChartType = xlXYScatterLines
    
    End Sub
    

    Исходные данные / диапазоны и итоговая Chart после Chart кода

    Обратите внимание, что формула SERIES включает в себя "B" для названия серии вместо ссылки на Range который ее создал.

    данные и итоговая диаграмма

    Создание пустой диаграммы

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

    Ключ к ChartObject определяет его местоположение. Синтаксис вызова — ChartObjects.Add(Left, Top, Width, Height) . После создания ChartObject вы можете использовать его объект Chart для фактического изменения диаграммы. ChartObject ведет себя больше как Shape чтобы расположить диаграмму на листе.

    Код для создания пустой диаграммы

    Sub CreateEmptyChart()
        
        'get reference to ActiveSheet
        Dim sht As Worksheet
        Set sht = ActiveSheet
        
        'create a new ChartObject at position (0, 0) with width 400 and height 300
        Dim chtObj As ChartObject
        Set chtObj = sht.ChartObjects.Add(0, 0, 400, 300)
        
        'get refernce to chart object
        Dim cht As Chart
        Set cht = chtObj.Chart
        
        'additional code to modify the empty chart
        '...
    
    End Sub
    

    Результирующая диаграмма

    пример пустой диаграммы

    Создание диаграммы путем изменения формулы SERIES

    Для полного контроля над новым объектом Chart и Series (особенно для динамического названия Series ) вы должны прибегнуть к модификации формулы SERIES напрямую. Процесс создания объектов Range является простым, и основным препятствием является просто построение строки для формулы SERIES .

    Формула SERIES принимает следующий синтаксис:

    =SERIES(Name,XValues,Values,Order)
    

    Это содержимое может быть предоставлено в виде ссылок или значений массива для элементов данных. Order представляет собой серию позиций в диаграмме. Обратите внимание, что ссылки на данные не будут работать, если они не полностью соответствуют имени листа. Для примера рабочей формулы щелкните любую существующую серию и проверьте панель формул.

    Код для создания диаграммы и настройки данных с использованием формулы SERIES

    Обратите внимание, что построение строки для создания формулы SERIES использует .Address(,,,True) . Это гарантирует, что ссылка внешнего диапазона используется так, чтобы был включен полный адрес с именем листа. Вы получите сообщение об ошибке, если имя листа исключено .

    Sub CreateChartUsingSeriesFormula()
    
        Dim xData As Range
        Dim yData As Range
        Dim serName As Range
        
        'set the ranges to get the data and y value label
        Set xData = Range("B3:B12")
        Set yData = Range("C3:C12")
        Set serName = Range("C2")
        
        'get reference to ActiveSheet
        Dim sht As Worksheet
        Set sht = ActiveSheet
        
        'create a new ChartObject at position (48, 195) with width 400 and height 300
        Dim chtObj As ChartObject
        Set chtObj = sht.ChartObjects.Add(48, 195, 400, 300)
        
        'get refernce to chart object
        Dim cht As Chart
        Set cht = chtObj.Chart
        
        'create the new series
        Dim ser As Series
        Set ser = cht.SeriesCollection.NewSeries
        
        'set the SERIES formula
        '=SERIES(name, xData, yData, plotOrder)
        
        Dim formulaValue As String
        formulaValue = "=SERIES(" & _
            serName.Address(, , , True) & "," & _
            xData.Address(, , , True) & "," & _
            yData.Address(, , , True) & ",1)"
        
        ser.Formula = formulaValue
        ser.ChartType = xlXYScatterLines
    
    End Sub
    

    Исходные данные и итоговая диаграмма

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

    данные и диаграмма из формулы SERIES

    Размещение диаграмм в сетке

    Обычная работа с графиками в Excel — это стандартизация размера и компоновки нескольких диаграмм на одном листе. Если сделать это вручную, вы можете удерживать ALT при изменении размера или перемещении диаграммы, чтобы «придерживаться» границ ячеек. Это работает для пары диаграмм, но подход VBA намного проще.

    Код для создания сетки

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

    Sub CreateGridOfCharts()
    
        Dim int_cols As Integer
        int_cols = 3
        
        Dim cht_width As Double
        cht_width = 250
            
        Dim cht_height As Double
        cht_height = 200
        
        Dim offset_vertical As Double
        offset_vertical = 195
        
        Dim offset_horz As Double
        offset_horz = 40
    
        Dim sht As Worksheet
        Set sht = ActiveSheet
    
        Dim count As Integer
        count = 0
        
        'iterate through ChartObjects on current sheet
        Dim cht_obj As ChartObject
        For Each cht_obj In sht.ChartObjects
            
            'use integer division and Mod to get position in grid
            cht_obj.Top = (count  int_cols) * cht_height + offset_vertical
            cht_obj.Left = (count Mod int_cols) * cht_width + offset_horz
            cht_obj.Width = cht_width
            cht_obj.Height = cht_height
    
            count = count + 1
    
        Next cht_obj
    End Sub
    

    Результат с несколькими графиками

    Эти снимки показывают исходную случайную компоновку диаграмм и результирующую сетку от запуска кода выше.

    До

    перед изображением нескольких диаграмм

    После

    сетка диаграмм

    Диаграмма по выделенной ячейке

    Предположим, что нам с вами требуется визуализировать данные из вот такой таблицы со значениями продаж автомобилей по разным странам в 2021 году (реальные данные, взятые отсюда, кстати):

    Исходные данные

    Поскольку количество рядов данных (стран) велико, то попытка запихнуть их все сразу в один график приведёт либо к ужасной «спагетти-диаграмме», либо к построению отдельных диаграмм на каждый ряд, что весьма громоздко.

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

    Результат

    Реализовать такое очень легко — потребуется лишь две формулы и один крохотный макрос в 3 строки.

    Шаг 1. Номер текущей строки

    Первое, что нам потребуется — это именованный диапазон, вычисляющий номер строки на листе, где сейчас стоит наша активная ячейка. Открываем на вкладке Формулы — Диспетчер имен (Formulas — Name manager), жмём на кнопку Создать (Create) и вводим туда следующую конструкцию:

    Ссылка на текущую строку

    Здесь:

    • Имя — любое подходящее имя для нашей переменной (в нашем случае это ТекСтрока)
    • Область — здесь и далее нужно выбрать текущий лист, чтобы создаваемые имена были локальными
    • Диапазон — тут используем функцию ЯЧЕЙКА (CELL), которая умеет выдавать кучу разных параметров для заданной ячейки, в том числе и нужный нам номер строки — за это отвечает аргумент «строка».

    Шаг 2. Ссылка на заголовок

    Для отображения выбранной страны в заголовке и легенде диаграммы, нам нужно получить ссылку на ячейку с её (страны) названием из первого столбца. Для этого создаём еще один локальный (т.е. Область = текущий лист, а не Книга!) именованный диапазон со следующей формулой:

    Ссылка на заголовок

    Здесь функция ИНДЕКС выбирает из заданного диапазона (столбца А, где лежат наши страны-подписи) ячейку с номером строки, который мы до этого определили.

    Шаг 3. Ссылка на данные

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

    Ссылка на данные

    Здесь третий аргумент равный нулю заставляет ИНДЕКС вернуть в качестве результата не отдельное значение, а всю строку.

    Шаг 4. Подставляем ссылки в диаграмму

    Теперь выделим шапку таблицы и первую строку с данными (диапазон    ) и построим по ним диаграмму через Вставка — Диаграммы (Insert — Charts). Если выделить на диаграмме ряд с данными, то в строке формул отобразится функция РЯД (SERIES) — специальная функция, которую Excel автоматически использует при создании любой диаграммы, чтобы сослаться на исходные данные и подписи:

    Функция РЯД

    Аккуратно подменим в этой функции первый (подпись) и третий (данные) аргументы названиями наших диапазонов с шагов 2 и 3:

    Подменяем ссылки

    Диаграмма начнет отображать данные по продажам из текущей строки.

    Шаг 5. Макрос пересчета

    Остался последний штрих. Microsoft Excel пересчитывает формулы только при изменении данных на листе или при нажатии на клавишу F9, а мы хотим, чтобы пересчёт происходил при изменении выделения, т. е. при любом перемещении активной ячейки по листу. Для этого потребуется добавить в нашу книгу простой макрос.

    Щёлкните правой кнопкой мыши по ярлычку листа с данными и выберите команду Исходный код (Source code). В открывшееся окно введём код макроса-обработчика события изменения выделения:

    Добавляем макрос пересчета на событие изменения выделения

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

    Шаг 6. Подсветка текущей строки

    Для наглядности, можно добавить ещё и правило условного форматирования для выделения цветом страны, которая сейчас отображается на графике. Для этого выделим таблицу и выберем Главная — Условное форматирование — Создать правило — Использовать формулу для определения форматируемых ячеек (Home — Conditional formatting — New rule — Use a formula to determine which cells to format):

    Добавляем подсветку строки

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

    Вот и всё — просто и красиво, правда?

    Примечания

    • На больших таблицах вся эта красота может тормозить — условное форматирование штука ресурсоёмкая, да и пересчёт на каждое выделение тоже может быть тяжеловат.
    • Чтобы на графике не пропадали данные при случайном выделении ячейки выше или ниже таблицы, можно добавить в имя ТекСтрока дополнительную проверку вложенными функциями ЕСЛИ вида:

      =ЕСЛИ(ЯЧЕЙКА(«строка»)<4;4;ЕСЛИ(ЯЧЕЙКА(«строка»)>20;20;ЯЧЕЙКА(«строка»)))

    Ссылки по теме

    • Подсветка заданных столбцов на диаграмме
    • Как создать в Excel интерактивную диаграмму
    • Координатное выделение

    Время на прочтение
    7 мин

    Количество просмотров 8.9K

    Доброго времени суток, уважаемые Хабровчане.

    Я — начинающий разработчик SharePoint, и сегодня хотелось бы рассказать о решении одной интересной задачи. Нужно было сделать веб-часть для SharePoint, которая должна обрабатывать таблицу с данными, выводить график на экран, а так же уметь экспортировать таблицу и график в Microsoft Excel. Под катом мой способ решения, отрывки кода веб-части и ссылка на проект.

    Теоретическое решение

    1. Построение графика на странице.

    Удобнее всего это делать с помощью MS Chart Control. Сам процесс достаточно прост (хотя, конечно, зависит от необходимого Вам вида графика). Единственное требование: первый столбец в таблице — это значения для оси X на графике.

    2. Экспорт таблицы в Excel

    Существует достаточно много способов экспорта, но я решил воспользоваться самым простым (на мой взгляд). Как известно, в Office 2007/2010 для файлов .docx, .xlsx, pptx используется формат Open XML, то есть эти файлы представляют из себя простой ZIP-архив с XML-файлами. Работать с ZIP-архивами просто, и таким образом можно записать данные напрямую в XML-файлы.
    Однако оказалось, что записать табличку с названиями столбцов не так то просто. Excel записывает цифровые поля напрямую в sheet1.xml, а текстовые поля записывает в sharedStrings.xml, и в sheet1.xml идут только ссылки на них. К счастью, я нашел замечательный проект, который и реализует запись текстовых значений в xlsx-файл.

    3. Экспорт графика в Excel

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

    Практическое решение

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

    DataTable dt = new DataTable();
    protected void Page_Load(object sender, EventArgs e)
            {
                for (int i = 0; i < 4;i++ )
                    dt.Columns.Add();
                dt.Rows.Add(new string[] { "Номер недели", "Печеньки", "Чай", "Сахар" });
                dt.Rows.Add(new string[] { "1", "17", "5", "8" });
                dt.Rows.Add(new string[] { "2", "18", "4", "10" });
                dt.Rows.Add(new string[] { "3", "15", "6", "9" });
                dt.Rows.Add(new string[] { "4", "19", "7", "10" });
                dt.Rows.Add(new string[] { "5", "13", "4", "7" });
                GridView1.DataSource = dt;
                GridView1.DataBind();
                GridView1.Width = 300;
                GridView1.ShowHeader = false;
            }

    Теперь делаем вывод графика. Учитываем, что данные начинаются со 2-й строки, а 1-й столбец — это значения для оси X.

                Series[] series = new Series[dt.Columns.Count - 1];
                for (int i = 0; i < series.Length; i++)
                {
                    series[i] = new Series(dt.Columns[i + 1].ColumnName);
                    series[i].ChartType = SeriesChartType.Column;
                    for (int k = 1; k < dt.Rows.Count; k++)
                        series[i].Points.AddXY((double.Parse((string)dt.Rows[k][0])), double.Parse((string)dt.Rows[k][i + 1]));
                    Chart1.Series.Add(series[i]);
                }
                ChartArea chartArea = new ChartArea();
                chartArea.AxisX.Minimum = double.Parse(dt.Rows[1][0].ToString());
                chartArea.AxisX.Maximum = double.Parse(dt.Rows[dt.Rows.Count - 1][0].ToString());
                Chart1.ChartAreas.Add(chartArea);
                Chart1.Width = 300;
                Chart1.Visible = true;
    

    Приступим к экспорту. Первое что понадобится — шаблон (пустой файл с графиком). Создаем в Excel новую книгу, вставляем график, указываем области данных. Сохраняем, закрываем. Можно немного отредактировать напрямую через xml — удалить кэшированные значения, если таблица не фиксированного размера — то в качестве областей данных можно подставить свои числа (я так схитрил — потом просто через Replace заменяю эти числа на необходимые). Шаблон надо закинуть в корневую папку узла Sharepoint.
    Используя вышеупомянутый проект, дорабатываем его под наши цели — сначала создадим копию 1й строки таблицы (названия столбцов). С помощью HashTable создадим ссылки на эти текстовые данные, а сами данные запишем в sharedStrings.xml.

    public static ArrayList CreateStringTables(DataTable data, out Hashtable lookupTable)
            {
                ArrayList stringTable = new ArrayList();
                lookupTable = new Hashtable();
    
                foreach (DataRow row in data.Rows)
                    foreach (DataColumn column in data.Columns)
                        if (column.DataType == typeof(string))
                        {
                            string val = (string)row[column];
                            if (!lookupTable.Contains(val))
                            {
                                lookupTable.Add(val, stringTable.Count);
                                stringTable.Add(val);
                            }
                        }
                return stringTable;
            }
            public static void WriteStringTable(Stream output, ArrayList stringTable)
            {
                using (XmlTextWriter writer = new XmlTextWriter(output, Encoding.UTF8))
                {
                    writer.WriteStartDocument(true);
                    writer.WriteRaw("<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="" + stringTable.Count.ToString() + "" uniqueCount="" + stringTable.Count.ToString() + "">");
                    foreach (string str in stringTable)
                    {
                        writer.WriteRaw("<si><t>" + str + "</t></si>");
                    }
                    writer.WriteRaw("</sst>");
                }
            }

    Теперь преобразуем таблицу данных в xml-код, попутно вставляя ссылки на текстовые данные. Записываем все в файл sheet1.xml.

    public static void WriteWorksheetData(XmlTextWriter writer, DataTable dt, Hashtable lookupTable)
            {
                int rowsCount = dt.Rows.Count;
                int columnsCount = dt.Columns.Count;
                string relPos = RowIndexToName(0);
                writer.WriteRaw("<row r="" + relPos + "" spans="1:" + columnsCount.ToString()+"">");
                for (int column = 0; column < columnsCount; column++)
                {
                    relPos = RowColumnToPosition(0, column);
                    writer.WriteRaw("<c r="" + relPos + "" t="s">");
                    string val = lookupTable[dt.Rows[0][column]].ToString();
                    writer.WriteRaw("<v>" + val + "</v>");
                    writer.WriteRaw("</c>");
                }
                writer.WriteRaw("</row>");
                for (int row = 1; row < rowsCount; row++)
                {
                    relPos = RowIndexToName(row);
                    writer.WriteRaw("<row r="" + relPos + "" spans="1:" + columnsCount.ToString() + "">");
                    for (int column = 0; column < columnsCount; column++)
                    {
                        relPos = RowColumnToPosition(row, column);
                        writer.WriteRaw("<c r="" + relPos + "">");
                        string val = dt.Rows[row][column].ToString();
                        writer.WriteRaw("<v>" + val + "</v>");
                        writer.WriteRaw("</c>");
                    }
                    writer.WriteRaw("</row>");
                }
            }
    public static void WriteWorksheet(Stream output, DataTable dt, Hashtable lookupTable)
            {
                using (XmlTextWriter writer = new XmlTextWriter(output, Encoding.UTF8))
                {
                    writer.WriteStartDocument(true);
                    writer.WriteRaw("<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">");
                    string lastCell = RowColumnToPosition(dt.Rows.Count - 1, dt.Columns.Count - 1);
                    writer.WriteRaw("<dimension ref="A1:" + lastCell + "" />");
                    writer.WriteRaw("<sheetViews>");
                    writer.WriteRaw("<sheetView tabSelected="1" workbookViewId="0" />");
                    writer.WriteRaw("</sheetViews>");
                    writer.WriteRaw("<sheetFormatPr defaultRowHeight="15" />");
                    writer.WriteRaw("<sheetData>");
                    WriteWorksheetData(writer, dt, lookupTable);
                    writer.WriteRaw("</sheetData>");
                    writer.WriteRaw("<pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3" />");
                    writer.WriteRaw("<drawing r:id="rId1" />");
                    writer.WriteRaw("</worksheet>");
                }
            }

    Осталось не забыть изменить области данных. Так как в начально проекте у меня могло быть не более пяти столбцов — я создал шаблон с пятью столбцами, а потом удалял лишние. Кол-во строк рассчитывается просто из таблицы.

    public static void FieldEdit(Stream xmlFile, int rowsCount, int columnsCount)
            {
                XmlDocument document = new XmlDocument();
                document.Load(xmlFile);
                XmlNodeList xmlColumns = document.GetElementsByTagName("c:ser");
                XmlNode xmlChart = xmlColumns[0].ParentNode;
                for (int i = xmlColumns.Count - 1; i > columnsCount - 2; i--)
                    xmlColumns[i].ParentNode.RemoveChild(xmlColumns[i]);
                XmlNodeList xmlRows = document.GetElementsByTagName("c:f");
                for (int i = 0; i < xmlRows.Count; i++)
                    xmlRows[i].InnerText = xmlRows[i].InnerText.Replace("15", rowsCount.ToString());
                MemoryStream ms = new MemoryStream();
                document.Save(ms);
                xmlFile.SetLength(ms.Length);
                xmlFile.Position = 0;
                document.Save(xmlFile);
                ms.Close();
            }

    И вот наш файл готов! Выдаем его пользователю для сохранения/загрузки с помощью HttpContext.Current.Response.

    public static void SendContent(byte[] fileContent, string outFileName)
            {
                HttpContext.Current.Response.ClearContent();
                HttpContext.Current.Response.AddHeader("Content-Type", "application/force-download");
                HttpContext.Current.Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}", outFileName.Replace(" ", "_")));
                HttpContext.Current.Response.AddHeader("Content-Length", fileContent.Length.ToString());
                HttpContext.Current.Response.OutputStream.Write(fileContent, 0, fileContent.Length);
                HttpContext.Current.Response.OutputStream.Flush();
                HttpContext.Current.Response.OutputStream.Close();
                HttpContext.Current.Response.Flush();
                HttpContext.Current.ApplicationInstance.CompleteRequest();
            }

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

    Примечания:

    • Изначально проект делался для SP2007 в VS2008, и портировался на 2010 специально для Хабра. Поэтому использованы не все возможности 2010 версии.
    • Код написан как пример, максимально просто, без ненужных (в данном случае) try-catch и т.д. Главное было показать идею, а не реализацию.
    • Этот способ можно использовать не только с SharePoint, но это наиболее часто встречающаяся связка с Excel.
    • Я только учусь, так что с удовольствием выслушаю Ваши советы и указания на мои ошибки.

    Спасибо за внимание.

    Like this post? Please share to your friends:
  • Когда появилась программа excel
  • Код для лицензии excel
  • Код для кнопки в excel
  • Код для записи в excel
  • Код для входа в word