C# 不同系列之间的StackedBar边框

C# 不同系列之间的StackedBar边框,c#,.net,c#-4.0,charts,mschart,C#,.net,C# 4.0,Charts,Mschart,我想要的是在StackedBar中的两个系列之间设置边框,如下图所示,蓝色和绿色之间的粗黑线 我想不出任何办法来指定边框,我试图通过这段代码将边框设置为序列 chart.Series["series0"].BorderWidth = 2; chart.Series["series0"].BorderColor = Color.Black; chart.Series["series0"].Border

我想要的是在StackedBar中的两个系列之间设置边框,如下图所示,蓝色和绿色之间的粗黑线

我想不出任何办法来指定边框,我试图通过这段代码将边框设置为序列

                chart.Series["series0"].BorderWidth = 2;
                chart.Series["series0"].BorderColor = Color.Black;
                chart.Series["series0"].BorderDashStyle = ChartDashStyle.Solid;
但这是我得到的结果

这是我的密码

 double l = Convert.ToDouble(query1[i - 1][0]) - 10;
                    string n = query1[i - 1][1];
                    int count = 0;
                for (double t = l; t < l + 10; t++)
                {

                        //Next line Calc. the occurence of character in a text file
                        count = n.Split('C').Length - 1;
                        //Multiple the occurence by 10 so it become percent
                        chart.Series["series0"].Points.AddXY(t, count * 10);
                        chart.Series["series0"]["PointWidth"] = "1";
                        chart.Series["series0"].BorderWidth = 2;
                        chart.Series["series0"].BorderColor = Color.Black;
                        chart.Series["series0"].BorderDashStyle = ChartDashStyle.Solid;


                        count = n.Split('o').Length - 1;
                        chart.Series["series1"].Points.AddXY(t, count * 10);
                        chart.Series["series1"]["PointWidth"] = "1";

                }
double l=Convert.ToDouble(查询1[i-1][0])-10;
字符串n=query1[i-1][1];
整数计数=0;
对于(双t=l;t

如何使用StackedBar实现第一个pic效果,如果我不能使用StackedBar,您建议使用哪种图表类型???

没有内置的图表元素可以轻松地在这两个系列之间形成边界。(创建
LineAnnotations
来实现这一点将是一场噩梦……)

因此,添加线的方法是将它们绘制到
图表的表面上。这是最自然地在
PostPaint
事件中完成的,仅为此类装饰提供

此处,
具有方便的功能,可在数据值和像素位置之间进行转换。我们需要
ValueToPixelPosition
方法

我将带您了解
图表
绘图的各种变化,随着我们接近最终版本,这些变化会逐渐变得更加复杂

让我们从一个简单的例子开始:让我们构建并装饰一个
StackedArea
图表;以下是图纸代码:

private void chart2_PostPaint(object sender, ChartPaintEventArgs e)
{
    Series s = chart1.Series[0];
    ChartArea ca = chart1.ChartAreas[0];
    var pp = s.Points.Select(x=>
        new PointF( (float)ca.AxisX.ValueToPixelPosition(x.XValue),
                    (float)ca.AxisY.ValueToPixelPosition(x.YValues[0])  )   );

    if (s.Points.Count >  1) 
        using (Pen pen = new Pen(Color.DarkOliveGreen, 4f))
            e.ChartGraphics.Graphics.DrawLines(pen, pp.ToArray());
}
指向。Select
实际上只是循环的简写;因此,在创建像素点列表后,我们只需绘制它

现在,正如您所看到的,as
StackedArea
图表是尖锐的,看起来不像
StackedBar
StackedColumn
图表。因此,让我们通过添加几个额外的点来欺骗和“纠正”面积图:

void rectifyArea(Series s)
{
    for (int i = s.Points.Count - 1; i > 0; i--)
        s.Points.InsertXY(i, i - 1, s.Points[i].YValues[0]);
}
结果:

现在这并不难;不幸的是,您无法将堆叠区域从左向右,而不是从下至上。因此,我们最终需要将图表类型更改为
Bar
类型

这里的挑战是找到这些条的右上下角。我们确实有
DataPoint
值,但这些值位于条的中间。因此,我们需要加上/减去条宽的一半来得到角。为此,我们需要宽度

当您使用
PointWidth
属性将其设置为
1
时,我们真正需要的是像素宽度。我们最好通过减去两个相邻点的像素坐标得到它

这使得
延迟
事件稍微长一点,但仍然不会过于复杂;我们将从一个
StackedColumn
图表开始,为每个数据点添加两个角点:

private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
    Series s = chart1.Series[0];
    ChartArea ca = chart1.ChartAreas[0];
    if (s.Points.Count <= 0) return;

    // calculate width of a column:
    int pp1 = (int)ca.AxisX.ValueToPixelPosition(s.Points[0].XValue);
    int pp2 = (int)ca.AxisX.ValueToPixelPosition(s.Points[1].XValue);
    float w2 = Math.Abs(pp2 - pp1) / 2f;

    List<PointF> points = new List<PointF>();
    for (int i = 0; i < s.Points.Count; i++)
    {
        DataPoint dp = s.Points[i];
        points.Add(new PointF( (int)ca.AxisX.ValueToPixelPosition(dp.XValue) - w2,
                               (int)ca.AxisY.ValueToPixelPosition(dp.YValues[0]) ));

        points.Add(new PointF( (int)ca.AxisX.ValueToPixelPosition(dp.XValue) + w2,
                               (int)ca.AxisY.ValueToPixelPosition(dp.YValues[0]) ));
    }

    if (points.Count > 1)
        using (Pen pen = new Pen(Color.DarkOliveGreen, 4f))
            e.ChartGraphics.Graphics.DrawLines(pen, points.ToArray());
}
请注意,我正在使用4像素的固定笔宽进行绘图。要使其与
图表缩放,您可能需要动态计算笔宽

更新

要在几个系列的顶部绘制边框,可以将代码放入如下循环中:

private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
    Chart  chart = chart1;
    Series s0 = chart.Series[0];
    ChartArea ca = chart.ChartAreas[0];

    // calculate width of a bar:
    int pp1 = (int)ca.AxisX.ValueToPixelPosition(s0.Points[0].XValue);
    int pp2 = (int)ca.AxisX.ValueToPixelPosition(s0.Points[1].XValue);
    float delta = Math.Abs(pp2 - pp1) / 2f;

    for (int s = 0; s < chart.Series.Count; s++)
    {
       List<PointF> points = new List<PointF>();
       for (int p = 0; p < chart.Series[s].Points.Count; p++)
       {
         DataPoint dp = chart.Series[s].Points[p];
         double v = GetStackTopValue(chart, s, p);
         points.Add(new PointF((float)ca.AxisY.ValueToPixelPosition(v),
                                (float)ca.AxisX.ValueToPixelPosition(dp.XValue) + delta));
         points.Add(new PointF((float)ca.AxisY.ValueToPixelPosition(v),
                               (float)ca.AxisX.ValueToPixelPosition(dp.XValue) - delta));
        }
        using (Pen pen = new Pen(Color.DarkOliveGreen, 3f))
            e.ChartGraphics.Graphics.DrawLines(pen, points.ToArray());
    }
}

double GetStackTopValue(Chart chart, int series, int point)
{
    double v = 0;
    for (int i = 0; i < series + 1; i++)
        v += chart.Series[i].Points[point].YValues[0];
    return v;
}
private void chart1_PostPaint(对象发送方,ChartPaintEventArgs e)
{
图表=图表1;
s0系列=图表系列[0];
ChartArea ca=chart.ChartAreas[0];
//计算钢筋的宽度:
int pp1=(int)ca.AxisX.ValueToPixelPosition(s0.Points[0].XValue);
int pp2=(int)ca.AxisX.ValueToPixelPosition(s0.Points[1].XValue);
浮动增量=数学绝对值(pp2-pp1)/2f;
对于(int s=0;s
谢谢,除了最后几行关于stackedbar的内容外,其他内容都很好,需要反转标志,。。。()在第一行签名,在第二行(+)。也可用于更多系列??如果我想像4个系列一样彼此分开,。。。我应该注意代码中的某些东西还是相同的方法?对不起,在我完成注释之前,我按了回车键,。。我再次编辑了评论,…所有作品现在都很好。是的,相同的原则可以应用于许多系列。这就是您需要更改的内容:因为y值是堆叠的,所以您需要将它们的总和输入到转换函数中。这是两个意甲联赛的一个例子
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
    Chart  chart = chart1;
    Series s0 = chart.Series[0];
    ChartArea ca = chart.ChartAreas[0];

    // calculate width of a bar:
    int pp1 = (int)ca.AxisX.ValueToPixelPosition(s0.Points[0].XValue);
    int pp2 = (int)ca.AxisX.ValueToPixelPosition(s0.Points[1].XValue);
    float delta = Math.Abs(pp2 - pp1) / 2f;

    for (int s = 0; s < chart.Series.Count; s++)
    {
       List<PointF> points = new List<PointF>();
       for (int p = 0; p < chart.Series[s].Points.Count; p++)
       {
         DataPoint dp = chart.Series[s].Points[p];
         double v = GetStackTopValue(chart, s, p);
         points.Add(new PointF((float)ca.AxisY.ValueToPixelPosition(v),
                                (float)ca.AxisX.ValueToPixelPosition(dp.XValue) + delta));
         points.Add(new PointF((float)ca.AxisY.ValueToPixelPosition(v),
                               (float)ca.AxisX.ValueToPixelPosition(dp.XValue) - delta));
        }
        using (Pen pen = new Pen(Color.DarkOliveGreen, 3f))
            e.ChartGraphics.Graphics.DrawLines(pen, points.ToArray());
    }
}

double GetStackTopValue(Chart chart, int series, int point)
{
    double v = 0;
    for (int i = 0; i < series + 1; i++)
        v += chart.Series[i].Points[point].YValues[0];
    return v;
}