Поделиться через


Вставка диаграммы в документ электронной таблицы

Дата последнего изменения: 13 января 2011 г.

Применимо к: Excel 2010 | Office 2010 | PowerPoint 2010 | Word 2010

В этой статье
Получение объекта SpreadsheetDocument
Базовая структура документа SpreadsheetML
Элемент строки
Элемент ячейки
Элемент значения ячейки
Механизм работы примера кода
Пример кода

В этом разделе описывается использование классов в пакете SDK Open XML версии 2.0 для Microsoft Office для вставки диаграмм в документ электронной таблицы программным способом.

Для компиляции кода, представленного в этом разделе, требуются следующие директивы сборки.

using System.Collections.Generic;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Drawing.Charts;
using DocumentFormat.OpenXml.Drawing.Spreadsheet;
Imports System.Collections.Generic
Imports System.Linq
Imports DocumentFormat.OpenXml
Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Spreadsheet
Imports DocumentFormat.OpenXml.Drawing
Imports DocumentFormat.OpenXml.Drawing.Charts
Imports DocumentFormat.OpenXml.Drawing.Spreadsheet

Получение объекта SpreadsheetDocument

Класс SpreadsheetDocument в пакете Open XML SDK представляет пакет документа Excel. Чтобы открыть документ Excel и работать с ним, нужно создать экземпляр класса SpreadsheetDocument из документа. После создания экземпляра из документа можно получить доступ к основной части книги, которая содержит листы. Содержимое документа представлено в этом пакете в виде XML-кода с использованием разметки SpreadsheetML.

Чтобы создать экземпляр класса на основе документа, нужно вызвать один из методов Open(). Доступно несколько таких методов с разными сигнатурами. В примере кода в этом разделе используется метод Open(String, Boolean) с сигнатурой, требующей два параметра. Первый параметр принимает строку с полным путем, представляющим открываемый документ. Во второй параметр передается значение true или false, указывающее, нужно ли открыть файл для редактирования. Если этот параметр имеет значение false, никакие изменения в документе сохранены не будут.

Код, вызывающий метод Open, показан в следующей инструкции using.

// Open the document for editing.
using (SpreadsheetDocument document = SpreadsheetDocument.Open(docName, true)) 
{
    // Insert other code here.
}
' Open the document for editing.
Using document As SpreadsheetDocument = SpreadsheetDocument.Open(docName, True)
    ' Insert other code here.
End Using

Инструкцию using рекомендуется использовать вместо традиционной последовательности .Open, .Save, .Close. Это позволяет обеспечить автоматический вызов метода Dispose (внутреннего метода, используемого пакетом SDK Open XML для очистки ресурсов) при достижении закрывающей скобки. Блок, следующий за инструкцией using, создает область для объекта, создаваемого или именуемого в инструкции using, в данном случае — document.

Базовая структура документа SpreadsheetML

Базовая структура документа SpreadsheetML состоит из элементов <sheets> и <sheet>, которые соответствуют листам в Workbook. Для каждого Worksheet создается отдельный XML-файл. Например, разметка SpreadsheetML для рабочей книги с тремя листами MySheet1, MySheet2 и Chart1 находится в файле Workbook.xml и представлена в следующем примере кода.

<x:workbook xmlns:r="https://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x="https://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <x:fileVersion appName="xl" lastEdited="5" lowestEdited="4" rupBuild="9302" />
  <x:workbookPr filterPrivacy="1" defaultThemeVersion="124226" />
  <x:bookViews>
    <x:workbookView xWindow="240" yWindow="108" windowWidth="14808" windowHeight="8016" activeTab="1" />
  </x:bookViews>
  <x:sheets>
    <x:sheet name="MySheet1" sheetId="1" r:id="rId1" />
    <x:sheet name="MySheet2" sheetId="2" r:id="rId2" />
    <x:sheet name="Chart1" sheetId="3" type="chartsheet" r:id="rId3"/>
  </x:sheets>
  <x:calcPr calcId="122211" />
</x:workbook>

XML-файлы листов содержат один или несколько элементов уровня блока, таких как <sheetData>, которые представляют таблицу ячеек и содержат один или несколько элементов строк (<row>). Элемент строки содержит один или несколько элементов ячеек (<c>). Каждый элемент ячейки содержит элемент значения ячейки (<v>). Например, код SpreadsheetML для первого листа в книге, в котором только у ячейки A1 имеется значение (100), находится в файле Sheet1.xml и представлен в следующем примере.

<?xml version="1.0" encoding="UTF-8" ?> 
<worksheet xmlns="https://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <sheetData>
        <row r="1">
            <c r="A1">
                <v>100</v> 
            </c>
        </row>
    </sheetData>
</worksheet>

При использовании пакета SDK Open XML версии 2.0 можно создать структуру и содержимое документа с помощью строго типизированных классов, соответствующих элементам SpreadsheetML. Эти классы находятся в пространстве имен DocumentFormat.OpenXml.Spreadsheet. В следующей таблице представлены имена классов, соответствующих элементам workbook, Sheets, Sheet, worksheet и SheetData

Элемент SpreadsheetML

Класс SDK Open XML версии 2.0

Описание

workbook

DocumentFormat.OpenXml.Spreadsheet.Workbook

Корневой элемент основной части документа.

sheets

DocumentFormat.OpenXml.Spreadsheet.Sheets

Контейнер для структур уровня блока, таких как sheet, fileVersion и другие, определенные в стандарте ISO/IEC 29500 (Возможно, на английском языке).

sheet

DocumentFormat.OpenXml.Spreadsheet.Sheet

Лист, указывающий на файл определения листа.

worksheet

DocumentFormat.OpenXml.Spreadsheet.Worksheet

Файл определения листа, который содержит данные листа.

sheetData

DocumentFormat.OpenXml.Spreadsheet.SheetData

Таблица ячеек, сгруппированная по строкам.

row

Row

Строка в таблице ячеек.

c

Cell

Ячейка в строке.

v

CellValue

Значение ячейки.

Элемент строки

В этом примере рассматривается работа с элементами строки, ячейки и значения ячейки. Поэтому предварительно рекомендуется ознакомиться с этими элементами. В следующей выдержке из стандарта ISO/IEC 29500 (Возможно, на английском языке) представляется элемент (<row>).

Элемент row содержит сведения о целой строке листа и определения всех ячеек из этой строки.

В следующем элементе представлены сведения о строке №2 в листе и содержатся определения 3 ячеек.

<row r="2" spans="2:12">
  <c r="C2" s="1">
    <f>PMT(B3/12,B4,-B5)</f>
    <v>672.68336574300008</v>
  </c>
  <c r="D2">
    <v>180</v>
  </c>
  <c r="E2">
    <v>360</v>
  </c>
</row>

© ISO/IEC29500: 2008.

В следующем примере кода XML Schema определяется содержимое элемента row.

<complexType name="CT_Row">
   <sequence>
       <element name="c" type="CT_Cell" minOccurs="0" maxOccurs="unbounded"/>
       <element name="extLst" minOccurs="0" type="CT_ExtensionList"/>
   </sequence>
   <attribute name="r" type="xsd:unsignedInt" use="optional"/>
   <attribute name="spans" type="ST_CellSpans" use="optional"/>
   <attribute name="s" type="xsd:unsignedInt" use="optional" default="0"/>
   <attribute name="customFormat" type="xsd:boolean" use="optional" default="false"/>
   <attribute name="ht" type="xsd:double" use="optional"/>
   <attribute name="hidden" type="xsd:boolean" use="optional" default="false"/>
   <attribute name="customHeight" type="xsd:boolean" use="optional" default="false"/>
   <attribute name="outlineLevel" type="xsd:unsignedByte" use="optional" default="0"/>
   <attribute name="collapsed" type="xsd:boolean" use="optional" default="false"/>
   <attribute name="thickTop" type="xsd:boolean" use="optional" default="false"/>
   <attribute name="thickBot" type="xsd:boolean" use="optional" default="false"/>
   <attribute name="ph" type="xsd:boolean" use="optional" default="false"/>
</complexType>

Элемент ячейки

В следующей выдержке из стандарта ISO/IEC 29500 (Возможно, на английском языке) представляется элемент ячейки (<c>).

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

В этом примере показаны данные, сохраненные для ячейки C6, имеющей стиль с индексом 6 и метаданные значения с индексом 15. Ячейка содержит формулу и вычисленный результат этой формулы.

<c r="C6" s="1" vm="15">
  <f>CUBEVALUE("xlextdat9 Adventure Works",C$5,$A6)</f>
  <v>2838512.355</v>
</c>

© ISO/IEC29500: 2008.

В следующем примере кода XML Schema определяется содержимое этого элемента.

<complexType name="CT_Cell">
   <sequence>
       <element name="f" type="CT_CellFormula" minOccurs="0" maxOccurs="1"/>
       <element name="v" type="ST_Xstring" minOccurs="0" maxOccurs="1"/>
       <element name="is" type="CT_Rst" minOccurs="0" maxOccurs="1"/>
       <element name="extLst" minOccurs="0" type="CT_ExtensionList"/>
   </sequence>
   <attribute name="r" type="ST_CellRef" use="optional"/>
   <attribute name="s" type="xsd:unsignedInt" use="optional" default="0"/>
   <attribute name="t" type="ST_CellType" use="optional" default="n"/>
   <attribute name="cm" type="xsd:unsignedInt" use="optional" default="0"/>
   <attribute name="vm" type="xsd:unsignedInt" use="optional" default="0"/>
   <attribute name="ph" type="xsd:boolean" use="optional" default="false"/>
</complexType>

Элемент значения ячейки

В следующей выдержке из стандарта ISO/IEC 29500 (Возможно, на английском языке) представляется элемент значения ячейки (<c>).

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

В приложениях, в которых не используется таблица общих строк, можно указать "внутреннюю строку" в элементе <is> под элементом <c> (вместо элемента <v> под элементом <c>), таким же образом строка была бы представлена в таблице общих строк.

© ISO/IEC29500: 2008.

В следующем примере ячейка B4 содержит число 360.

<c r="B4">
  <v>360</v>
</c>

Механизм работы примера кода

После открытия файла электронной таблицы с доступом для чтения и записи код проверяет, существует ли указанный лист. Затем с помощью метода AddNewPart на лист добавляется новый объект DrawingsPart, после чего сохраняется часть листа. Затем код добавляет новый объект ChartPart, новый объект ChartSpace к объекту ChartPart и после этого — новый объект EditingLanguage к объекту ChartSpace, в котором задается язык диаграммы, English-US.

IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.Descendants<Sheet>().Where
    (s => s.Name == worksheetName);
if (sheets.Count() == 0)
{
    // The specified worksheet does not exist.
    return;
}
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheets.First().Id);

// Add a new drawing to the worksheet.
DrawingsPart drawingsPart = worksheetPart.AddNewPart<DrawingsPart>();
worksheetPart.Worksheet.Append(new DocumentFormat.OpenXml.Spreadsheet.Drawing() 
    { Id = worksheetPart.GetIdOfPart(drawingsPart) });
worksheetPart.Worksheet.Save();

// Add a new chart and set the chart language to English-US.
ChartPart chartPart = drawingsPart.AddNewPart<ChartPart>();
chartPart.ChartSpace = new ChartSpace();
chartPart.ChartSpace.Append(new EditingLanguage() { Val = new StringValue("en-US") });
DocumentFormat.OpenXml.Drawing.Charts.Chart chart = chartPart.ChartSpace.AppendChild 
    <DocumentFormat.OpenXml.Drawing.Charts.Chart>
    (new DocumentFormat.OpenXml.Drawing.Charts.Chart());
Dim sheets As IEnumerable(Of Sheet) = _
    document.WorkbookPart.Workbook.Descendants(Of Sheet)() _
    .Where(Function(s) s.Name = worksheetName)
If sheets.Count() = 0 Then
    ' The specified worksheet does not exist.
    Return
End If
Dim worksheetPart As WorksheetPart = _
    CType(document.WorkbookPart.GetPartById(sheets.First().Id), WorksheetPart)

' Add a new drawing to the worksheet.
Dim drawingsPart As DrawingsPart = worksheetPart.AddNewPart(Of DrawingsPart)()
worksheetPart.Worksheet.Append(New DocumentFormat.OpenXml.Spreadsheet.Drawing() With {.Id = _
              worksheetPart.GetIdOfPart(drawingsPart)})
worksheetPart.Worksheet.Save()

' Add a new chart and set the chart language to English-US.
Dim chartPart As ChartPart = drawingsPart.AddNewPart(Of ChartPart)()
chartPart.ChartSpace = New ChartSpace()
chartPart.ChartSpace.Append(New EditingLanguage() With {.Val = _
                            New StringValue("en-US")})
Dim chart As DocumentFormat.OpenXml.Drawing.Charts.Chart = _
    chartPart.ChartSpace.AppendChild(Of DocumentFormat.OpenXml.Drawing.Charts _
        .Chart)(New DocumentFormat.OpenXml.Drawing.Charts.Chart())

Код создает гистограмму с группировкой путем создания объекта BarChart, где для объекта BarDirectionValues задано значение Column, а для объекта BarGroupingValues задано значение Clustered.

Затем происходит перебор всех ключей в классе Dictionary. Для каждого ключа объект BarChartSeries добавляется к объекту BarChart и объекту SeriesText объекта BarChartSeries присваивается значение ключа. Для каждого ключа объект NumberLiteral добавляется к коллекции Values объекта BarChartSeries и объекту NumberLiteral присваивается значение класса Dictionary, соответствующее ключу.

// Create a new clustered column chart.
PlotArea plotArea = chart.AppendChild<PlotArea>(new PlotArea());
Layout layout = plotArea.AppendChild<Layout>(new Layout());
BarChart barChart = plotArea.AppendChild<BarChart>(new BarChart(new BarDirection() 
    { Val = new EnumValue<BarDirectionValues>(BarDirectionValues.Column) },
    new BarGrouping() { Val = new EnumValue<BarGroupingValues> BarGroupingValues.Clustered) }));

uint i = 0;

// Iterate through each key in the Dictionary collection and add the key to the chart Series
// and add the corresponding value to the chart Values.
foreach (string key in data.Keys)
{
    BarChartSeries barChartSeries = barChart.AppendChild<BarChartSeries>
        (new BarChartSeries(new Index() { Val = new UInt32Value(i) },
        new Order() { Val = new UInt32Value(i) },
        new SeriesText(new NumericValue() { Text = key })));

    StringLiteral strLit = barChartSeries.AppendChild<CategoryAxisData>
    (new CategoryAxisData()).AppendChild<StringLiteral>(new StringLiteral());
    strLit.Append(new PointCount() { Val = new UInt32Value(1U) });
    strLit.AppendChild<StringPoint>(new StringPoint() { Index = new UInt32Value(0U) })
.Append(new NumericValue(title));

    NumberLiteral numLit = barChartSeries.AppendChild<DocumentFormat.
OpenXml.Drawing.Charts.Values>(new DocumentFormat.OpenXml.Drawing.Charts.Values()).AppendChild<NumberLiteral>
    (new NumberLiteral());
    numLit.Append(new FormatCode("General"));
    numLit.Append(new PointCount() { Val = new UInt32Value(1U) });
    numLit.AppendChild<NumericPoint>(new NumericPoint() { Index = new UInt32Value(0u)})
    .Append(new NumericValue(data[key].ToString()));

    i++;
}
' Create a new clustered column chart.
Dim plotArea As PlotArea = chart.AppendChild(Of PlotArea)(New PlotArea())
Dim layout As Layout = plotArea.AppendChild(Of Layout)(New Layout())
Dim barChart As BarChart = plotArea.AppendChild(Of BarChart)(New BarChart _
    (New BarDirection() With {.Val = New EnumValue(Of BarDirectionValues) _
    (BarDirectionValues.Column)}, New BarGrouping() With {.Val = New EnumValue _
    (Of BarGroupingValues)(BarGroupingValues.Clustered)}))

Dim i As UInteger = 0

' Iterate through each key in the Dictionary collection and add the key to the chart Series
' and add the corresponding value to the chart Values.
For Each key As String In data.Keys
    Dim barChartSeries As BarChartSeries = barChart.AppendChild(Of BarChartSeries) _
        (New BarChartSeries(New Index() With {.Val = New UInt32Value(i)}, New Order() _
        With {.Val = New UInt32Value(i)}, New SeriesText(New NumericValue() With {.Text = key})))

    Dim strLit As StringLiteral = barChartSeries.AppendChild(Of CategoryAxisData) _
        (New CategoryAxisData()).AppendChild(Of StringLiteral)(New StringLiteral())
    strLit.Append(New PointCount() With {.Val = New UInt32Value(1UI)})
    strLit.AppendChild(Of StringPoint)(New StringPoint() With {.Index = _
        New UInt32Value(0UI)}).Append(New NumericValue(title))

    Dim numLit As NumberLiteral = barChartSeries.AppendChild _
        (Of DocumentFormat.OpenXml.Drawing.Charts.Values)(New DocumentFormat _
        .OpenXml.Drawing.Charts.Values()).AppendChild(Of NumberLiteral)(New NumberLiteral())
    numLit.Append(New FormatCode("General"))
    numLit.Append(New PointCount() With {.Val = New UInt32Value(1UI)})
    numLit.AppendChild(Of NumericPoint)(New NumericPoint() With {.Index = _
        New UInt32Value(0UI)}).Append(New NumericValue(data(key).ToString()))

    i += 1
Next key

В коде в диаграмму добавляются объекты CategoryAxis и ValueAxis и задается значение следующих свойств: Scaling, AxisPosition, TickLabelPosition, CrossingAxis, Crosses, AutoLabeled, LabelAlignment и LabelOffset. Кроме того, в диаграмму добавляется объект Legend и сохраняется часть диаграммы.

barChart.Append(new AxisId() { Val = new UInt32Value(48650112u) });
barChart.Append(new AxisId() { Val = new UInt32Value(48672768u) });

// Add the Category Axis.
CategoryAxis catAx = plotArea.AppendChild<CategoryAxis>(new CategoryAxis(new AxisId() 
    { Val = new UInt32Value(48650112u) }, new Scaling(new Orientation()
    {
        Val = new EnumValue<DocumentFormat.OpenXml.Drawing.Charts.OrientationValues>(
            DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax)
    }),
    new AxisPosition() { Val = new EnumValue<AxisPositionValues>(AxisPositionValues.Bottom) },
    new TickLabelPosition() { Val = new EnumValue<TickLabelPositionValues>(TickLabelPositionValues.NextTo) },
    new CrossingAxis() { Val = new UInt32Value(48672768U) },
    new Crosses() { Val = new EnumValue<CrossesValues>(CrossesValues.AutoZero) },
    new AutoLabeled() { Val = new BooleanValue(true) },
    new LabelAlignment() { Val = new EnumValue<LabelAlignmentValues>(LabelAlignmentValues.Center) },
    new LabelOffset() { Val = new UInt16Value((ushort)100) }));

// Add the Value Axis.
ValueAxis valAx = plotArea.AppendChild<ValueAxis>(new ValueAxis(new AxisId() { Val = new UInt32Value(48672768u) },
    new Scaling(new Orientation()
    {
        Val = new EnumValue<DocumentFormat.OpenXml.Drawing.Charts.OrientationValues>(
            DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax)
    }),
    new AxisPosition() { Val = new EnumValue<AxisPositionValues>(AxisPositionValues.Left) },
    new MajorGridlines(),
    new DocumentFormat.OpenXml.Drawing.Charts.NumberingFormat() { FormatCode = new StringValue("General"), 
    SourceLinked = new BooleanValue(true) }, new TickLabelPosition() { Val = 
    new EnumValue<TickLabelPositionValues>(TickLabelPositionValues.NextTo) },
    new CrossingAxis() { Val = new UInt32Value(48650112U) }, new Crosses() {
    Val = new EnumValue<CrossesValues>(CrossesValues.AutoZero) }, new CrossBetween()
{ Val = new EnumValue<CrossBetweenValues>(CrossBetweenValues.Between) }));
// Add the chart Legend.
Legend legend = chart.AppendChild<Legend>(new Legend(new LegendPosition() 
  { Val = new EnumValue<LegendPositionValues>(LegendPositionValues.Right) },
    new Layout()));

chart.Append(new PlotVisibleOnly() { Val = new BooleanValue(true) });

// Save the chart part.
chartPart.ChartSpace.Save();
barChart.Append(New AxisId() With {.Val = New UInt32Value(48650112UI)})
barChart.Append(New AxisId() With {.Val = New UInt32Value(48672768UI)})

' Add the Category Axis.
Dim catAx As CategoryAxis = plotArea.AppendChild(Of CategoryAxis) _ 
    (New CategoryAxis(New AxisId() With {.Val = New UInt32Value(48650112UI)}, _ 
New Scaling(New Orientation() With {.Val = New EnumValue(Of _
 DocumentFormat.OpenXml.Drawing.Charts.OrientationValues) _
(DocumentFormat.Open Xml.Drawing.Charts.OrientationValues.MinMax)}), New AxisPosition() With _
{.Val = New EnumValue(Of AxisPositionValues)(AxisPositionValues.Bottom)}, _
New TickLabelPosition() With {.Val = New EnumValue(Of TickLabelPositionValues) _
(TickLabelPositionValues.NextTo)}, New CrossingAxis() With {.Val = New UInt32Value(48672768UI)}, _
New Crosses() With {.Val = New EnumValue(Of CrossesValues)(CrossesValues.AutoZero)} _
, New AutoLabeled() With {.Val = New BooleanValue(True)}, New LabelAlignment()_
 With {.Val = New EnumValue(Of LabelAlignmentValues)(LabelAlignmentValues.Center)} _
, New LabelOffset() With {.Val = New UInt16Value(CUShort(100))}))

' Add the Value Axis.
Dim valAx As ValueAxis = plotArea.AppendChild(Of ValueAxis)(New ValueAxis _
    (New AxisId() With {.Val = New UInt32Value(48672768UI)}, New Scaling(New  _
    Orientation() With {.Val = New EnumValue(Of DocumentFormat.OpenXml.Drawing _
    .Charts.OrientationValues)(DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax)}), _
    New AxisPosition() With {.Val = New EnumValue(Of AxisPositionValues)(AxisPositionValues.Left)}, _
    New MajorGridlines(), New DocumentFormat.OpenXml.Drawing.Charts.NumberingFormat() With {.FormatCode = _
    New StringValue("General"), .SourceLinked = New BooleanValue(True)}, New TickLabelPosition() With _
    {.Val = New EnumValue(Of TickLabelPositionValues)(TickLabelPositionValues.NextTo)}, New CrossingAxis() _
    With {.Val = New UInt32Value(48650112UI)}, New Crosses() With {.Val = New EnumValue(Of CrossesValues) _
    (CrossesValues.AutoZero)}, New CrossBetween() With {.Val = New EnumValue(Of CrossBetweenValues) _
    (CrossBetweenValues.Between)}))

' Add the chart Legend.
Dim legend As Legend = chart.AppendChild(Of Legend)(New Legend(New LegendPosition() _
    With {.Val = New EnumValue(Of LegendPositionValues)(LegendPositionValues.Right)}, New Layout()))

chart.Append(New PlotVisibleOnly() With {.Val = New BooleanValue(True)})

' Save the chart part.
chartPart.ChartSpace.Save()

В коде диаграмма размещается на листе путем создания объекта WorksheetDrawing и добавления объекта TwoCellAnchor. Объект TwoCellAnchor определяет, как изменяется положение или размер диаграммы при перемещении строк и столбцов между привязками FromMarker и ToMarker. Затем создается объект GraphicFrame, в котором будет содержаться диаграмма, и ей присваивается имя "Chart 1", после чего документ листа сохраняется.

// Position the chart on the worksheet using a TwoCellAnchor object.
drawingsPart.WorksheetDrawing = new WorksheetDrawing();
TwoCellAnchor twoCellAnchor = drawingsPart.WorksheetDrawing.AppendChild<TwoCellAnchor>(new TwoCellAnchor());
twoCellAnchor.Append(new DocumentFormat.OpenXml.Drawing.Spreadsheet.FromMarker(new ColumnId("9"),
    new ColumnOffset("581025"),
    new RowId("17"),
    new RowOffset("114300")));
twoCellAnchor.Append(new DocumentFormat.OpenXml.Drawing.Spreadsheet.ToMarker(new ColumnId("17"),
    new ColumnOffset("276225"),
    new RowId("32"),
    new RowOffset("0")));

// Append a GraphicFrame to the TwoCellAnchor object.
DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame graphicFrame = 
    twoCellAnchor.AppendChild<DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame>(
    new DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame());
graphicFrame.Macro = "";

graphicFrame.Append(new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualGraphicFrameProperties(
    new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties() { Id = new UInt32Value(2u), 
Name = "Chart 1" }, new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualGraphicFrameDrawingProperties()));

graphicFrame.Append(new Transform(new Offset() { X = 0L, Y = 0L },
                    new Extents() { Cx = 0L, Cy = 0L }));

graphicFrame.Append(new Graphic(new GraphicData(new ChartReference() { Id = drawingsPart.GetIdOfPart(chartPart)})
{ Uri = "https://schemas.openxmlformats.org/drawingml/2006/chart" }));

twoCellAnchor.Append(new ClientData());

// Save the WorksheetDrawing object.
drawingsPart.WorksheetDrawing.Save();
' Position the chart on the worksheet using a TwoCellAnchor object.
drawingsPart.WorksheetDrawing = New WorksheetDrawing()
Dim twoCellAnchor As TwoCellAnchor = drawingsPart.WorksheetDrawing.AppendChild(Of  _
    TwoCellAnchor)(New TwoCellAnchor())
twoCellAnchor.Append(New DocumentFormat.OpenXml.Drawing.Spreadsheet.FromMarker(New  _
    ColumnId("9"), New ColumnOffset("581025"), New RowId("17"), New RowOffset("114300")))
twoCellAnchor.Append(New DocumentFormat.OpenXml.Drawing.Spreadsheet.ToMarker(New  _
    ColumnId("17"), New ColumnOffset("276225"), New RowId("32"), New RowOffset("0")))

' Append a GraphicFrame to the TwoCellAnchor object.
Dim graphicFrame As DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame = _
    twoCellAnchor.AppendChild(Of DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame) _
    (New DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame())
graphicFrame.Macro = ""

graphicFrame.Append(New DocumentFormat.OpenXml.Drawing.Spreadsheet _
    .NonVisualGraphicFrameProperties(New DocumentFormat.OpenXml.Drawing.Spreadsheet. _
    NonVisualDrawingProperties() With {.Id = New UInt32Value(2UI), .Name = "Chart 1"}, _
    New DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualGraphicFrameDrawingProperties()))

graphicFrame.Append(New Transform(New Offset() With {.X = 0L, .Y = 0L}, _
    New Extents() With {.Cx = 0L, .Cy = 0L}))

graphicFrame.Append(New Graphic(New GraphicData(New ChartReference() With _
    {.Id = drawingsPart.GetIdOfPart(chartPart)}) With {.Uri = _
    "https://schemas.openxmlformats.org/drawingml/2006/chart"}))

twoCellAnchor.Append(New ClientData())

' Save the WorksheetDrawing object.
drawingsPart.WorksheetDrawing.Save()

Пример кода

В следующем коде в пакет документа SpreadsheetDocument добавляется гистограмма с группировкой с использованием данных класса Dictionary<TKey, TValue>. С помощью данного фрагмента кода можно, например, вызывать метод InsertChartInSpreadsheet.

string docName = @"C:\Users\Public\Documents\Sheet6.xlsx";
string worksheetName = "Joe";
string title = "New Chart";
Dictionary<string,int> data = new Dictionary<string,int>();
data.Add("abc", 1);
InsertChartInSpreadsheet(docName, worksheetName, title, data);
Dim docName As String = "C:\Users\Public\Documents\Sheet6.xlsx"
Dim worksheetName As String = "Joe"
Dim title As String = "New Chart"
Dim data As New Dictionary(Of String, Integer)()
data.Add("abc", 1)
InsertChartInSpreadsheet(docName, worksheetName, title, data)

После запуска программы откройте файл с названием "Sheet6.xlsx", чтобы просмотреть вставленную диаграмму.

Примечание

Этот код можно запускать только один раз. Нельзя создать больше одного экземпляра диаграммы.

Ниже приведен полный пример кода на языках C# и Visual Basic.

// Given a document name, a worksheet name, a chart title, and a Dictionary collection of text keys
// and corresponding integer data, creates a column chart with the text as the series and the integers as the values.
private static void InsertChartInSpreadsheet(string docName, string worksheetName, string title, 
Dictionary<string, int> data)
{
    // Open the document for editing.
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(docName, true))
    {
        IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.Descendants<Sheet>().
Where(s => s.Name == worksheetName);
        if (sheets.Count() == 0)
        {
            // The specified worksheet does not exist.
            return;
        }
        WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheets.First().Id);

        // Add a new drawing to the worksheet.
        DrawingsPart drawingsPart = worksheetPart.AddNewPart<DrawingsPart>();
        worksheetPart.Worksheet.Append(new DocumentFormat.OpenXml.Spreadsheet.Drawing()
    { Id = worksheetPart.GetIdOfPart(drawingsPart) });
        worksheetPart.Worksheet.Save();

        // Add a new chart and set the chart language to English-US.
        ChartPart chartPart = drawingsPart.AddNewPart<ChartPart>(); 
        chartPart.ChartSpace = new ChartSpace();
        chartPart.ChartSpace.Append(new EditingLanguage() { Val = new StringValue("en-US") });
        DocumentFormat.OpenXml.Drawing.Charts.Chart chart = chartPart.ChartSpace.AppendChild<DocumentFormat.OpenXml.Drawing.Charts.Chart>(
            new DocumentFormat.OpenXml.Drawing.Charts.Chart());

        // Create a new clustered column chart.
        PlotArea plotArea = chart.AppendChild<PlotArea>(new PlotArea());
        Layout layout = plotArea.AppendChild<Layout>(new Layout());
        BarChart barChart = plotArea.AppendChild<BarChart>(new BarChart(new BarDirection() 
            { Val = new EnumValue<BarDirectionValues>(BarDirectionValues.Column) },
            new BarGrouping() { Val = new EnumValue<BarGroupingValues>(BarGroupingValues.Clustered) }));

        uint i = 0;
        
        // Iterate through each key in the Dictionary collection and add the key to the chart Series
        // and add the corresponding value to the chart Values.
        foreach (string key in data.Keys)
        {
            BarChartSeries barChartSeries = barChart.AppendChild<BarChartSeries>(new BarChartSeries(new Index() { Val =
 new UInt32Value(i) },
                new Order() { Val = new UInt32Value(i) },
                new SeriesText(new NumericValue() { Text = key })));

            StringLiteral strLit = barChartSeries.AppendChild<CategoryAxisData>(new CategoryAxisData()).AppendChild<StringLiteral>(new StringLiteral());
            strLit.Append(new PointCount() { Val = new UInt32Value(1U) });
            strLit.AppendChild<StringPoint>(new StringPoint() { Index = new UInt32Value(0U) }).Append(new NumericValue(title));

            NumberLiteral numLit = barChartSeries.AppendChild<DocumentFormat.OpenXml.Drawing.Charts.Values>(
                new DocumentFormat.OpenXml.Drawing.Charts.Values()).AppendChild<NumberLiteral>(new NumberLiteral());
            numLit.Append(new FormatCode("General"));
            numLit.Append(new PointCount() { Val = new UInt32Value(1U) });
            numLit.AppendChild<NumericPoint>(new NumericPoint() { Index = new UInt32Value(0u) }).Append
(new NumericValue(data[key].ToString()));

            i++;
        }

        barChart.Append(new AxisId() { Val = new UInt32Value(48650112u) });
        barChart.Append(new AxisId() { Val = new UInt32Value(48672768u) });

        // Add the Category Axis.
        CategoryAxis catAx = plotArea.AppendChild<CategoryAxis>(new CategoryAxis(new AxisId() 
{ Val = new UInt32Value(48650112u) }, new Scaling(new Orientation() { Val = new EnumValue<DocumentFormat.
OpenXml.Drawing.Charts.OrientationValues>(                DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax) }),
            new AxisPosition() { Val = new EnumValue<AxisPositionValues>(AxisPositionValues.Bottom) },
            new TickLabelPosition() { Val = new EnumValue<TickLabelPositionValues>(TickLabelPositionValues.NextTo) },
            new CrossingAxis() { Val = new UInt32Value(48672768U) },
            new Crosses() { Val = new EnumValue<CrossesValues>(CrossesValues.AutoZero) },
            new AutoLabeled() { Val = new BooleanValue(true) },
            new LabelAlignment() { Val = new EnumValue<LabelAlignmentValues>(LabelAlignmentValues.Center) },
            new LabelOffset() { Val = new UInt16Value((ushort)100) }));

        // Add the Value Axis.
        ValueAxis valAx = plotArea.AppendChild<ValueAxis>(new ValueAxis(new AxisId() { Val = new UInt32Value(48672768u) },
            new Scaling(new Orientation() { Val = new EnumValue<DocumentFormat.OpenXml.Drawing.Charts.OrientationValues>(
                DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax) }),
            new AxisPosition() { Val = new EnumValue<AxisPositionValues>(AxisPositionValues.Left) },
            new MajorGridlines(),
            new DocumentFormat.OpenXml.Drawing.Charts.NumberingFormat() { FormatCode = new StringValue("General"), 
SourceLinked = new BooleanValue(true) }, new TickLabelPosition() { Val = new EnumValue<TickLabelPositionValues>
(TickLabelPositionValues.NextTo) }, new CrossingAxis() { Val = new UInt32Value(48650112U) },
            new Crosses() { Val = new EnumValue<CrossesValues>(CrossesValues.AutoZero) },
            new CrossBetween() { Val = new EnumValue<CrossBetweenValues>(CrossBetweenValues.Between) }));

        // Add the chart Legend.
        Legend legend = chart.AppendChild<Legend>(new Legend(new LegendPosition() { Val = new EnumValue<LegendPositionValues>(LegendPositionValues.Right) },
            new Layout()));

        chart.Append(new PlotVisibleOnly() { Val = new BooleanValue(true) });

        // Save the chart part.
        chartPart.ChartSpace.Save();

        // Position the chart on the worksheet using a TwoCellAnchor object.
        drawingsPart.WorksheetDrawing = new WorksheetDrawing();
        TwoCellAnchor twoCellAnchor = drawingsPart.WorksheetDrawing.AppendChild<TwoCellAnchor>(new TwoCellAnchor());
        twoCellAnchor.Append(new DocumentFormat.OpenXml.Drawing.Spreadsheet.FromMarker(new ColumnId("9"),
            new ColumnOffset("581025"),
            new RowId("17"),
            new RowOffset("114300")));
        twoCellAnchor.Append(new DocumentFormat.OpenXml.Drawing.Spreadsheet.ToMarker(new ColumnId("17"),
            new ColumnOffset("276225"),
            new RowId("32"),
            new RowOffset("0")));

        // Append a GraphicFrame to the TwoCellAnchor object.
        DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame graphicFrame = 
            twoCellAnchor.AppendChild<DocumentFormat.OpenXml.
Drawing.Spreadsheet.GraphicFrame>(new DocumentFormat.OpenXml.Drawing.
Spreadsheet.GraphicFrame());
        graphicFrame.Macro = "";

        graphicFrame.Append(new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualGraphicFrameProperties(
            new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties() { Id = new UInt32Value(2u), Name = "Chart 1" },
            new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualGraphicFrameDrawingProperties()));

        graphicFrame.Append(new Transform(new Offset() { X = 0L, Y = 0L },
                                                                new Extents() { Cx = 0L, Cy = 0L }));

        graphicFrame.Append(new Graphic(new GraphicData(new ChartReference()            { Id = drawingsPart.GetIdOfPart(chartPart) }) 
{ Uri = "https://schemas.openxmlformats.org/drawingml/2006/chart" }));

        twoCellAnchor.Append(new ClientData());

        // Save the WorksheetDrawing object.
        drawingsPart.WorksheetDrawing.Save();
    }

}
' Given a document name, a worksheet name, a chart title, and a Dictionary collection of text keys 
' and corresponding integer data, creates a column chart with the text as the series 
' and the integers as the values.
Private Sub InsertChartInSpreadsheet(ByVal docName As String, ByVal worksheetName As String, _
ByVal title As String, ByVal data As Dictionary(Of String, Integer))
    ' Open the document for editing.
    Using document As SpreadsheetDocument = SpreadsheetDocument.Open(docName, True)
        Dim sheets As IEnumerable(Of Sheet) = _
            document.WorkbookPart.Workbook.Descendants(Of Sheet)() _
            .Where(Function(s) s.Name = worksheetName)
        If sheets.Count() = 0 Then
            ' The specified worksheet does not exist.
            Return
        End If
        Dim worksheetPart As WorksheetPart = _
            CType(document.WorkbookPart.GetPartById(sheets.First().Id), WorksheetPart)

        ' Add a new drawing to the worksheet.
        Dim drawingsPart As DrawingsPart = worksheetPart.AddNewPart(Of DrawingsPart)()
        worksheetPart.Worksheet.Append(New DocumentFormat.OpenXml.Spreadsheet.Drawing() With {.Id = _
              worksheetPart.GetIdOfPart(drawingsPart)})
        worksheetPart.Worksheet.Save()

        ' Add a new chart and set the chart language to English-US.
        Dim chartPart As ChartPart = drawingsPart.AddNewPart(Of ChartPart)()
        chartPart.ChartSpace = New ChartSpace()
        chartPart.ChartSpace.Append(New EditingLanguage() With {.Val = _
                                    New StringValue("en-US")})
        Dim chart As DocumentFormat.OpenXml.Drawing.Charts.Chart = _
            chartPart.ChartSpace.AppendChild(Of DocumentFormat.OpenXml.Drawing.Charts _
                .Chart)(New DocumentFormat.OpenXml.Drawing.Charts.Chart())

        ' Create a new clustered column chart.
        Dim plotArea As PlotArea = chart.AppendChild(Of PlotArea)(New PlotArea())
        Dim layout As Layout = plotArea.AppendChild(Of Layout)(New Layout())
        Dim barChart As BarChart = plotArea.AppendChild(Of BarChart)(New BarChart _
            (New BarDirection() With {.Val = New EnumValue(Of BarDirectionValues) _
            (BarDirectionValues.Column)}, New BarGrouping() With {.Val = New EnumValue _
            (Of BarGroupingValues)(BarGroupingValues.Clustered)}))

        Dim i As UInteger = 0

        ' Iterate through each key in the Dictionary collection and add the key to the chart Series
        ' and add the corresponding value to the chart Values.
        For Each key As String In data.Keys
            Dim barChartSeries As BarChartSeries = barChart.AppendChild(Of BarChartSeries) _
                (New BarChartSeries(New Index() With {.Val = New UInt32Value(i)}, New Order() _
                With {.Val = New UInt32Value(i)}, New SeriesText(New NumericValue() With {.Text = key})))

            Dim strLit As StringLiteral = barChartSeries.AppendChild(Of CategoryAxisData) _
                (New CategoryAxisData()).AppendChild(Of StringLiteral)(New StringLiteral())
            strLit.Append(New PointCount() With {.Val = New UInt32Value(1UI)})
            strLit.AppendChild(Of StringPoint)(New StringPoint() With {.Index = _
                New UInt32Value(0UI)}).Append(New NumericValue(title))

            Dim numLit As NumberLiteral = barChartSeries.AppendChild _
                (Of DocumentFormat.OpenXml.Drawing.Charts.Values)(New DocumentFormat _
                .OpenXml.Drawing.Charts.Values()).AppendChild(Of NumberLiteral)(New NumberLiteral())
            numLit.Append(New FormatCode("General"))
            numLit.Append(New PointCount() With {.Val = New UInt32Value(1UI)})
            numLit.AppendChild(Of NumericPoint)(New NumericPoint() With {.Index = _
                New UInt32Value(0UI)}).Append(New NumericValue(data(key).ToString()))

            i += 1
        Next key

        barChart.Append(New AxisId() With {.Val = New UInt32Value(48650112UI)})
        barChart.Append(New AxisId() With {.Val = New UInt32Value(48672768UI)})

        ' Add the Category Axis.
        Dim catAx As CategoryAxis = plotArea.AppendChild(Of CategoryAxis) _
            (New CategoryAxis(New AxisId() With {.Val = New UInt32Value(48650112UI)}, New Scaling(New Orientation() With {.Val = New EnumValue(Of DocumentFormat.OpenXml.Drawing.Charts.OrientationValues)(DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax)}), New AxisPosition() With {.Val = New EnumValue(Of AxisPositionValues)(AxisPositionValues.Bottom)}, New TickLabelPosition() With {.Val = New EnumValue(Of TickLabelPositionValues)(TickLabelPositionValues.NextTo)}, New CrossingAxis() With {.Val = New UInt32Value(48672768UI)}, New Crosses() With {.Val = New EnumValue(Of CrossesValues)(CrossesValues.AutoZero)}, New AutoLabeled() With {.Val = New BooleanValue(True)}, New LabelAlignment() With {.Val = New EnumValue(Of LabelAlignmentValues)(LabelAlignmentValues.Center)}, New LabelOffset() With {.Val = New UInt16Value(CUShort(100))}))

        ' Add the Value Axis.
        Dim valAx As ValueAxis = plotArea.AppendChild(Of ValueAxis)(New ValueAxis _
            (New AxisId() With {.Val = New UInt32Value(48672768UI)}, New Scaling(New  _
            Orientation() With {.Val = New EnumValue(Of DocumentFormat.OpenXml.Drawing _
            .Charts.OrientationValues)(DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax)}), _
            New AxisPosition() With {.Val = New EnumValue(Of AxisPositionValues)(AxisPositionValues.Left)}, _
            New MajorGridlines(), New DocumentFormat.OpenXml.Drawing.Charts.NumberingFormat() With {.FormatCode = _
            New StringValue("General"), .SourceLinked = New BooleanValue(True)}, New TickLabelPosition() With _
            {.Val = New EnumValue(Of TickLabelPositionValues)(TickLabelPositionValues.NextTo)}, New CrossingAxis() _
            With {.Val = New UInt32Value(48650112UI)}, New Crosses() With {.Val = New EnumValue(Of CrossesValues) _
            (CrossesValues.AutoZero)}, New CrossBetween() With {.Val = New EnumValue(Of CrossBetweenValues) _
            (CrossBetweenValues.Between)}))

        ' Add the chart Legend.
        Dim legend As Legend = chart.AppendChild(Of Legend)(New Legend(New LegendPosition() _
            With {.Val = New EnumValue(Of LegendPositionValues)(LegendPositionValues.Right)}, New Layout()))

        chart.Append(New PlotVisibleOnly() With {.Val = New BooleanValue(True)})

        ' Save the chart part.
        chartPart.ChartSpace.Save()

        ' Position the chart on the worksheet using a TwoCellAnchor object.
        drawingsPart.WorksheetDrawing = New WorksheetDrawing()
        Dim twoCellAnchor As TwoCellAnchor = drawingsPart.WorksheetDrawing.AppendChild(Of  _
            TwoCellAnchor)(New TwoCellAnchor())
        twoCellAnchor.Append(New DocumentFormat.OpenXml.Drawing.Spreadsheet.FromMarker(New  _
            ColumnId("9"), New ColumnOffset("581025"), New RowId("17"), New RowOffset("114300")))
        twoCellAnchor.Append(New DocumentFormat.OpenXml.Drawing.Spreadsheet.ToMarker(New  _
            ColumnId("17"), New ColumnOffset("276225"), New RowId("32"), New RowOffset("0")))

        ' Append a GraphicFrame to the TwoCellAnchor object.
        Dim graphicFrame As DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame = _
            twoCellAnchor.AppendChild(Of DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame) _
            (New DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame())
        graphicFrame.Macro = ""

        graphicFrame.Append(New DocumentFormat.OpenXml.Drawing.Spreadsheet _
            .NonVisualGraphicFrameProperties(New DocumentFormat.OpenXml.Drawing.Spreadsheet. _
            NonVisualDrawingProperties() With {.Id = New UInt32Value(2UI), .Name = "Chart 1"}, _
            New DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualGraphicFrameDrawingProperties()))

        graphicFrame.Append(New Transform(New Offset() With {.X = 0L, .Y = 0L}, _
            New Extents() With {.Cx = 0L, .Cy = 0L}))

        graphicFrame.Append(New Graphic(New GraphicData(New ChartReference() With _
            {.Id = drawingsPart.GetIdOfPart(chartPart)}) With {.Uri = _
            "https://schemas.openxmlformats.org/drawingml/2006/chart"}))

        twoCellAnchor.Append(New ClientData())

        ' Save the WorksheetDrawing object.
        drawingsPart.WorksheetDrawing.Save()
    End Using

End Sub

См. также

Ссылка

Class Library Reference

Другие ресурсы

LINQ

Лямбда-выражения

Лямбда-выражения (руководство по программированию на C#)