.NET 图表图例标记大小
Posted
技术标签:
【中文标题】.NET 图表图例标记大小【英文标题】:.NET Charting Legend Marker Size 【发布时间】:2016-04-01 22:15:49 【问题描述】:我在 .NET Windows 窗体项目中使用 DataVisualizations Charting 控件。我遇到的问题是,当我打印图表时,图例没有显示系列标记(实际上它是一种显示,但它看起来像是线上的较暗像素)。当在表格上查看图表时,标记是可见的,尽管它们不是很大,并且相对于系列的 MarkerSize 值似乎没有变化。但是当图表被打印(在纸上或 PDF 上)时,标记不存在。
此图片显示了在表单上查看时的图表视图。如您所见,图例标记有点可见,但仍然没有接近实际系列标记的位置。
此图片显示了同一图表的 PDF 版本。如果你用力眯眼,你会在图例线的中心看到较暗的像素。
如何修复图例标记,以便它们在打印时实际显示并使其尺寸更大?
【问题讨论】:
我怀疑您能否以任何直接方式进行操作。图例标记的大小实际上确实随着标记大小而增长,但速度要慢得多。因此,一种解决方法是用您自己的图例替换真正的图例,您可以在其中使用动态绘制的图像。如果您有兴趣,我可能会在今天晚些时候向您展示一个示例.. 如果你能举个例子那就太好了。很想看看它的样子。 【参考方案1】:由于似乎无法控制图例标记,您可能需要创建自定义图例。以下是它在Form
和PDF
中的外观示例:
我不得不缩小 PDF,所以它看起来更薄/更轻。
这是一个返回CustomLegend
的函数:
Legend CustomCloneLegend(Chart chart, Legend oLeg)
Legend newL = new Legend();
newL.Position = oLeg.Position; // copy a few settings:
newL.Docking = oLeg.Docking;
newL.Alignment = oLeg.Alignment;
// a few numbers for the drawing to play with; you may want to use floats..
int iw = 32; int iw2 = iw / 2; int ih = 18; int ih2 = ih / 2;
int ir = 12; int ir2 = ir / 2; int lw = 3;
// we want to access the series' colors!
chart.ApplyPaletteColors();
foreach (Series S in chart.Series)
// the drawing code is only for linechart and markerstyles circle or square:
Bitmap bmp = new Bitmap(iw, ih);
using (Graphics G = Graphics.FromImage(bmp))
using (Pen pen = new Pen(S.Color, lw))
using (SolidBrush brush = new SolidBrush(S.Color))
G.DrawLine(pen, 0, ih2, iw, ih2);
if (S.MarkerStyle == MarkerStyle.Circle)
G.FillEllipse(brush, iw2 - ir2, ih2 - ir2, ir, ir);
else if (S.MarkerStyle == MarkerStyle.Square)
G.FillRectangle(brush, iw2 - ir2, ih2 - ir2, ir, ir);
// add a new NamesImage
NamedImage ni = new NamedImage(S.Name, bmp);
chart.Images.Add(ni);
// create and add the custom legend item
LegendItem lit = new LegendItem( S.Name, Color.Red, S.Name);
newL.CustomItems.Add(lit);
oLeg.Enabled = false;
return newL;
我是这样称呼它的:
Legend LC = CustomCloneLegend(chart3, L);
chart1.Legends.Add(LC);
几点说明:
代码使用chart.ApplyPaletteColors()
。这是访问Series
颜色所必需的。
它还利用了鲜为人知的类NamedImage
和Chart.Images
。这是必要的,因为在 Chart
中设置任何图像都需要一个字符串!
如果要放大图像,可能需要使用LegendCells
。例如see here!
我只为一个ChartType
(Line
) 和两个MarkerStyles
编码了图像绘图。
有很多方法可以自定义这些CustomItems
。更多信息请参见here..
我确实使用了Series.MarkerSize
,但是通过在循环中设置ir = S.MarkerSize;
等来调整代码很容易!
与我所做的 3 相比,您可能需要从原始图例复制更多设置到自定义图例。我刚刚注意到你设置了一个Font
..
【讨论】:
这绝对是完美的,也是我所需要的。谢谢。【参考方案2】:这是 TaW 解决方案的 VB 翻译。我添加了绘制三角形标记的代码,并注释掉了通过每个标记画一条线的代码,这样我更容易看到标记的形状。因此,您要么必须在调用此函数之前为每个系列设置 MarkerStyle,要么取消注释该行。
我的图表有一些额外的系列,可以在数据点周围绘制椭圆。我不想在图例中显示那些,所以我只显示具有命名 LegendText 的系列的图例条目。这些行在下面被注释掉,但如果你想要相同的行为,你可以取消注释。
Public Function CustomCloneLegend(chart As Chart, oLeg As Legend) As Legend
Dim newL As Legend = New Legend With
.Position = oLeg.Position,
.Docking = oLeg.Docking,
.Alignment = oLeg.Alignment,
.Font = oLeg.Font
' a few numbers for the drawing to play with'
Dim iw As Integer = 16
Dim iw2 As Integer = iw / 2
Dim ih As Integer = 16
Dim ih2 As Integer = ih / 2
Dim ir As Integer = 6
Dim ir2 As Integer = ir / 2
Dim lw As Integer = 3
Dim lit As LegendItem
' point array for drawing triangles, can expand to other shapes'
Dim pts(2) As Point
' we want to access the series colors!'
chart.ApplyPaletteColors()
For Each S As Series In chart.Series
ir = S.MarkerSize
' the drawing code Is only for linechart And markerstyles circle, square, triangle'
Dim bmp As Bitmap = New Bitmap(iw, ih)
Using G As Graphics = Graphics.FromImage(bmp)
Using pen As Pen = New Pen(S.Color, lw)
Using Brush As SolidBrush = New SolidBrush(S.Color)
' Commented out the next line: Makes it hard to see the marker 'shapes
'G.DrawLine(pen, 0, ih2, iw, ih2) '
Select Case S.MarkerStyle
Case MarkerStyle.Circle
G.FillEllipse(Brush, iw2 - ir2, ih2 - ir2, ir, ir)
Case MarkerStyle.Square
G.FillRectangle(Brush, iw2 - ir2, ih2 - ir2, ir, ir)
Case MarkerStyle.Triangle
pts(0) = New Point(iw2, ih2)
pts(1) = New Point(1, ih)
pts(2) = New Point(iw - 1, ih)
G.FillPolygon(Brush, pts)
End Select
' add a New NamesImage '
Dim ni As NamedImage = New NamedImage(S.Name, bmp)
chart.Images.Add(ni)
' create And add the custom legend item '
'Uncomment the If block to hide legend labels for series with no LegendText '
'If S.LegendText <> "" Then '
lit = New LegendItem(S.Name, Color.Red, S.Name) With
.MarkerStyle = MarkerStyle.None,
.ImageStyle = LegendImageStyle.Marker
newL.CustomItems.Add(lit)
'End If '
End Using
End Using
End Using
Next
oLeg.Enabled = False
Return newL
End Function
【讨论】:
以上是关于.NET 图表图例标记大小的主要内容,如果未能解决你的问题,请参考以下文章