.NET 图表图例标记大小

Posted

技术标签:

【中文标题】.NET 图表图例标记大小【英文标题】:.NET Charting Legend Marker Size 【发布时间】:2016-04-01 22:15:49 【问题描述】:

我在 .NET Windows 窗体项目中使用 DataVisualizations Charting 控件。我遇到的问题是,当我打印图表时,图例没有显示系列标记(实际上它是一种显示,但它看起来像是线上的较暗像素)。当在表格上查看图表时,标记是可见的,尽管它们不是很大,并且相对于系列的 MarkerSize 值似乎没有变化。但是当图表被打印(在纸上或 PDF 上)时,标记不存在。

此图片显示了在表单上查看时的图表视图。如您所见,图例标记有点可见,但仍然没有接近实际系列标记的位置。

此图片显示了同一图表的 PDF 版本。如果你用力眯眼,你会在图例线的中心看到较暗的像素。

如何修复图例标记,以便它们在打印时实际显示并使其尺寸更大?

【问题讨论】:

我怀疑您能否以任何直接方式进行操作。图例标记的大小实际上确实随着标记大小而增长,但速度要慢得多。因此,一种解决方法是用您自己的图例替换真正的图例,您可以在其中使用动态绘制的图像。如果您有兴趣,我可能会在今天晚些时候向您展示一个示例.. 如果你能举个例子那就太好了。很想看看它的样子。 【参考方案1】:

由于似乎无法控制图例标记,您可能需要创建自定义图例。以下是它在FormPDF 中的外观示例:

我不得不缩小 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 颜色所必需的。 它还利用了鲜为人知的类NamedImageChart.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 图表图例标记大小的主要内容,如果未能解决你的问题,请参考以下文章

Matplotlib 获取图例标记的坐标

如何在 MATLAB 2014b 的散点图中增加图例的标记大小? [复制]

为标记设置不透明度,但不在图例中

Plotly Dash 图例中的自定义标记

使用“大小”参数时调整散点图中的标记大小

ECharts 图表设置标记的大小 symbolSize 和获取标记的值