.NET Core中使用NPOI修改散点图样式的方法(移除连线、调整标记形状/颜色等)
.NET Core中使用NPOI修改散点图样式的方法(移除连线、调整标记形状/颜色等)
我之前用NPOI做散点图的时候也踩过这个坑!默认的散点之间会自动连上线条,密集的点直接糊成一团,完全失去了散点图的意义。下面就给你说解决方法,包括移除连线,还有一些常用的样式调整,都是我实际试过能用的:
首先,先解决移除散点间连线的问题。NPOI的高层图表API没有直接封装这个选项,我们需要直接操作底层的OpenXML对象(就是那些以CT_开头的类)。在你的代码里,创建完series并设置标题后,添加下面这段代码:
// 移除散点之间的连线 using NPOI.OpenXmlFormats.Drawing.Spreadsheet; // 获取底层的散点series对象 var ctScatterSer = series.GetCTScatterSer(); // 初始化形状属性(如果不存在的话) if (ctScatterSer.spPr == null) { ctScatterSer.spPr = new CT_ShapeProperties(); } if (ctScatterSer.spPr.ln == null) { ctScatterSer.spPr.ln = new CT_LineProperties(); } // 设置线条为无填充(也就是隐藏连线) ctScatterSer.spPr.ln.noFill = new CT_NoFillProperties();
这样就能把那些烦人的连线去掉了,只剩下独立的散点。
接下来是散点标记的样式调整,比如改形状、颜色、大小,同样是操作CT对象:
// 调整散点标记的形状(可选:circle、square、diamond、triangle等) if (ctScatterSer.marker == null) { ctScatterSer.marker = new CT_Marker(); } ctScatterSer.marker.symbol = CT_MarkerStyleVal.circle; // 设置标记的填充颜色(这里用的是十六进制FF5733,也就是橙色) if (ctScatterSer.marker.solidFill == null) { ctScatterSer.marker.solidFill = new CT_SolidColorFillProperties(); } ctScatterSer.marker.solidFill.srgbClr = new CT_SRgbColor(); ctScatterSer.marker.solidFill.srgbClr.val = System.Text.Encoding.ASCII.GetBytes("FF5733"); // 设置标记的大小(单位是pt的1/100,比如800就是8pt) ctScatterSer.marker.size = new CT_MarkerSize(); ctScatterSer.marker.size.val = 800;
如果想要修改图表标题的样式(比如加粗、改字号),也可以用类似的方式操作图表的底层对象:
// 调整标题的字体大小和加粗 var ctTitle = chart.GetCTChart().title; if (ctTitle.tx.rich.p == null) { ctTitle.tx.rich.p = new CT_TextParagraph[] { new CT_TextParagraph() }; } var titleTextPr = ctTitle.tx.rich.p[0].rPr = new CT_TextCharacterProperties(); titleTextPr.sz = new CT_PositiveSize2D(); titleTextPr.sz.val = 1400; // 14pt titleTextPr.b = new CT_Boolean(); titleTextPr.b.val = true; // 加粗
把这些代码整合到你的AddTempErrChart方法里,最终的代码大概是这样:
public static void AddTempErrChart(XSSFWorkbook wb, XSSFSheet sh, int r0, int c0, int nRows, int xOffset, int yOffset) { var draw = sh.CreateDrawingPatriarch() as XSSFDrawing; var anchor = draw.CreateAnchor(0, 0, 0, 0, c0, r0 + nRows + 2, c0 + 6, r0 + nRows + 17); var chart = draw.CreateChart(anchor) as XSSFChart; chart.SetTitle("Temp vs FitPresErr"); var bottom = chart.ChartAxisFactory.CreateValueAxis(AxisPosition.Bottom); var left = chart.ChartAxisFactory.CreateValueAxis(AxisPosition.Left); var data = chart.ChartDataFactory.CreateScatterChartData<double, double>(); // data ranges var xRange = new CellRangeAddress(r0 + 1, r0 + nRows, c0 + xOffset, c0 + xOffset); var yRange = new CellRangeAddress(r0 + 1, r0 + nRows, c0 + yOffset, c0 + yOffset); var xs = DataSources.FromNumericCellRange(sh, xRange); var ys = DataSources.FromNumericCellRange(sh, yRange); var series = data.AddSeries(xs, ys); series.SetTitle("run"); // ------------------ 样式修改部分开始 ------------------ using NPOI.OpenXmlFormats.Drawing.Spreadsheet; // 移除散点间的连线 var ctScatterSer = series.GetCTScatterSer(); if (ctScatterSer.spPr == null) { ctScatterSer.spPr = new CT_ShapeProperties(); } if (ctScatterSer.spPr.ln == null) { ctScatterSer.spPr.ln = new CT_LineProperties(); } ctScatterSer.spPr.ln.noFill = new CT_NoFillProperties(); // 调整散点标记:圆形、橙色、8pt大小 if (ctScatterSer.marker == null) { ctScatterSer.marker = new CT_Marker(); } ctScatterSer.marker.symbol = CT_MarkerStyleVal.circle; if (ctScatterSer.marker.solidFill == null) { ctScatterSer.marker.solidFill = new CT_SolidColorFillProperties(); } ctScatterSer.marker.solidFill.srgbClr = new CT_SRgbColor(); ctScatterSer.marker.solidFill.srgbClr.val = System.Text.Encoding.ASCII.GetBytes("FF5733"); ctScatterSer.marker.size = new CT_MarkerSize(); ctScatterSer.marker.size.val = 800; // 调整标题样式:14pt加粗 var ctTitle = chart.GetCTChart().title; if (ctTitle.tx.rich.p == null) { ctTitle.tx.rich.p = new CT_TextParagraph[] { new CT_TextParagraph() }; } var titleTextPr = ctTitle.tx.rich.p[0].rPr = new CT_TextCharacterProperties(); titleTextPr.sz = new CT_PositiveSize2D(); titleTextPr.sz.val = 1400; titleTextPr.b = new CT_Boolean(); titleTextPr.b.val = true; // ------------------ 样式修改部分结束 ------------------ chart.Plot(data, bottom, left); }
最后补充一句:因为NPOI的图表高层API封装得比较基础,很多精细的样式调整都需要直接操作底层的CT_*类,这些类对应的是Office Open XML的规范,如果你需要更复杂的样式(比如坐标轴网格线、背景色),可以去查ECMA-376的图表部分,或者直接看NPOI源码里的这些CT类的定义,找对应的属性调整就行。
内容来源于stack exchange




