在电子表格文档中插入图表
本主题演示如何使用 Open XML SDK for Office 中的类以编程方式将图表插入电子表格文档中。
Row 元素
在此帮助中,您将处理行、单元格和单元格值元素。 因此,熟悉这些元素会非常有用。
ISO/IEC 29500 规范中的以下文本介绍了行 (<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/IEC 29500:2016
以下 XML 架构代码示例定义行元素的内容。
<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>
Cell 元素
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/IEC 29500:2016
以下 XML 架构代码示例定义此元素的内容。
<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/>
) 元素。
此元素表示单元格中包含的值。 如果单元格包含字符串,则此值为共享字符串表中的索引,指向实际字符串值。 否则,该单元格的值会在此元素中直接表示。 包含公式的单元格表示此元素中的公式的最后一次计算结果。
对于不希望实现共享字符串表的应用程序,“内联字符串”可以用 (下的
<c/>
元素而不是<v/>
) 下的<c/>
元素来表示<is/>
,其方式与在共享字符串表中表示字符串的方式相同。© ISO/IEC 29500:2016
在下面的示例中,单元格 B4 包含数值 360。
<c r="B4">
<v>360</v>
</c>
示例代码的工作原理
打开电子表格以进行读/写访问后,该代码会验证指定工作表是否存在。 然后,它使用 AddNewPart 方法添加一个新DrawingsPart对象,将其追加到工作表,并保存工作表部件。 然后,代码会添加新 ChartPart 对象,将新 ChartSpace 对象追加到对象 ChartPart
,然后将新 EditingLanguage 对象追加到 ChartSpace
指定图表语言为英语-美国的对象。
IEnumerable<Sheet>? sheets = document.WorkbookPart?.Workbook.Descendants<Sheet>().Where(s => s.Name == worksheetName);
if (sheets is null || sheets.Count() == 0)
{
// The specified worksheet does not exist.
return;
}
string? id = sheets.First().Id;
if (id is null)
{
// The worksheet does not have an ID.
return;
}
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart!.GetPartById(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) });
// 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());
该代码通过创建一个新的 BarChart 对象,并将 BarDirectionValues 对象设置为 Column
,并将 BarGroupingValues 对象设置为 Clustered
来创建新的聚集柱形图。
然后,代码循环访问 类中的每个 Dictionary
键。 对于每个键,它会向 对象追加一个 BarChartSeries 对象,BarChart
并将 对象的 对象BarChartSeries
设置为SeriesText等于该键。 对于每个键,它会将一个 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++;
}
代码将 CategoryAxis 对象和 ValueAxis 对象添加到图表,并设置以下属性的值:Scaling、、AxisPosition、TickLabelPosition、CrossingAxisCrosses、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) });
代码通过创建 WorksheetDrawing 对象并追加 TwoCellAnchor
对象,在工作表上定位图表。 对象TwoCellAnchor
指定在 和 ToMarker 定位点之间移动行和列时FromMarker如何移动图表或调整其大小。 然后,代码创建一个 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 = "http://schemas.openxmlformats.org/drawingml/2006/chart" }));
twoCellAnchor.Append(new ClientData());
示例代码
注意
[!注释] 此代码只能运行一次。 不能创建该图表的多个实例。
以下是使用 C# 和 Visual Basic 编写的完整示例代码。
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 is null || sheets.Count() == 0)
{
// The specified worksheet does not exist.
return;
}
string? id = sheets.First().Id;
if (id is null)
{
// The worksheet does not have an ID.
return;
}
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart!.GetPartById(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) });
// 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) });
// 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 = "http://schemas.openxmlformats.org/drawingml/2006/chart" }));
twoCellAnchor.Append(new ClientData());
}
}