StackedBar不同系列之间的边界 [英] StackedBar borders between different series

查看:186
本文介绍了StackedBar不同系列之间的边界的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要的是在StackedBar中的两个系列之间设置边界像这个图像蓝色和绿色之间的粗黑线

What i want is to set borders between two series in StackedBar Like this image The bold black line between blue and green

我无法想出任何想法来指定边框,我试图设置边框到系列的这个代码

I can not figure out any idea to specify the border, i tried to set the borders to the series throuh this code

                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";

                }

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

How to achieve the first pic effect using StackedBar ? , if i can not using StackedBar, what chart type you suggest to use ??

推荐答案

可以很容易地形成这两个系列之间的边界。 (创建 LineAnnotations 以实现这将是一场噩梦..)

There are no built-in chart elements that could easily be made into a borderline between those two Series. (Creating LineAnnotations to achieve this would be a nightmare..)

所以添加行的方式是将它们绘制到图表的表面上。这是在 PostPaint 事件中自然完成的,只为这样的装饰。

So the way to add the lines is to draw them onto the surface of the Chart. This is most naturally done in the PostPaint event, provided just for such adornments.

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

Here the Axes have handy functions to convert between the data values and the pixel positions. We need the ValueToPixelPosition method.

code>绘图逐渐变得有点复杂,因为我们接近的最终版本..

I will take you through variations of Chart drawing that gradually get a little more complicated as we approach the final version..:

让我们开始一个简单的例子:让我们建立和装饰一个 StackedArea chart;这里是绘图代码:

Let's start with a simple example: Let's build and adorn a StackedArea chart; here is the drawing code:

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());
}

Points.Select 真的只是一个循环的简写;所以在创建像素点列表后,我们只需要绘制它。

The Points.Select is really just a shorthand for a loop; so after creating the pixel point list we simply draw it.

现在,如您所见, StackedArea 是尖的,并且看起来不像 StackedBar StackedColumn 图表。所以让我们通过添加一些额外的点来欺骗和纠正区域图:

Now, as you can see, as StackedArea chart is pointy and doesn't look like a StackedBar or StackedColumn chart. So let's cheat and 'rectify' the area chart by adding a few extra points:

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]);
}

结果:

现在没那么难了;不幸的是你不能把 StackedArea 从左到右而不是自下而上。因此,我们需要将图表类型更改为 Bar 类型。

Now that was not so hard; unfortunately you just can't turn a StackedArea to go from left to right instead of bottom-up. So we need to change the chart type to a Bar type eventually..

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

Here the challenge is to find the right upper and lower corners of those bars. We do have the DataPoint values, but these are in the middle of the bars. So we need to add/subtract half of the Bars' width to get the corners. For this we need the width.

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

While you have set it with the PointWidth property to 1, what we really need is the pixel width. We best get it by subtracting the pixel coordinates of two neighbouring points.

这使得 PostPaint ,但仍然不过分复杂;我们将从 StackedColumn 图表开始,为每个数据点添加两个角点:

This makes the PostPaint event a little longer, but still not overly complicated; we will start with a StackedColumn chart, adding two corner points for each data point:

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());
}

现在这看起来与我们的假版 '。我们需要更改什么才能将其应用于 StackedBar 图表?几乎没有!我们需要照顾的唯一两件事情是

Now this looks pretty much identical to our fake version of the 'rectified area chart'. What will we need to change to apply this to a StackedBar chart? Almost nothing! The only two things we need to take care of are


  • y轴的方向。由于点向上移动,但GDI +图形的像素坐标向下移动,我们需要以相反的顺序创建两个角点。
  • 我们需要反转x和y坐标,因为所有类型的 Bar 图表的轴都是相反的。 li>
  • the direction of the y-axis. Since the points move upward but the pixel coordinates of GDI+ graphhics move downwards we need to create the two cornerpoints in the reverse order.
  • And we need to reverse the x- and y coodinates, as the axes are reversed for all types of Bar charts.

以下是带有边框的两个堆叠图表:

Here are the two stacked charts with a border:

这是 StackBar 图表:

This is the loop for the StackBar chart:

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

请注意,我用4像素的固定笔宽度绘制。要使其与图表缩放,您可能需要动态计算笔宽度。

Note that I am drawing with a fixed pen width of 4 pixels. To make it scale with the Chart you may want to calculate the pen width dynamically..

更新

要绘制边框您可以将代码放入一个循环,如下所示:

To draw borders on top of several series you can put the code into a loop like this:

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;
}

这篇关于StackedBar不同系列之间的边界的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆