C# 结合条形图和点图

C# 结合条形图和点图,c#,charts,bar-chart,series,C#,Charts,Bar Chart,Series,我遇到了一个小问题,我想创建一个如下所示的图表: aSeries["DrawSideBySide"] = "false"; aSeries.SetCustomProperty("DrawSideBySide", "false"); 所以基本上 系列1=标准条形图。如果在“时间最大值”(系列2)系列2之前结束,则显示绿色=系列1项目顶部的数据点/标记 我正在努力解决这个问题 我的代码: chart_TimeChart.Series.Clear(); strin

我遇到了一个小问题,我想创建一个如下所示的图表:

aSeries["DrawSideBySide"] = "false";
aSeries.SetCustomProperty("DrawSideBySide", "false");

所以基本上 系列1=标准条形图。如果在“时间最大值”(系列2)系列2之前结束,则显示绿色=系列1项目顶部的数据点/标记

我正在努力解决这个问题

我的代码:

        chart_TimeChart.Series.Clear();
        string series_timeneeded = "Time Needed";
        chart_TimeChart.Series.Add(series_timeneeded);
        chart_TimeChart.Series[series_timeneeded]["PixelPointWidth"] = "5";
        chart_TimeChart.ChartAreas[0].AxisY.ScrollBar.Size = 10;
        chart_TimeChart.ChartAreas[0].AxisY.ScrollBar.ButtonStyle =    ScrollBarButtonStyles.SmallScroll;
        chart_TimeChart.ChartAreas[0].AxisY.ScrollBar.IsPositionedInside = true;
        chart_TimeChart.ChartAreas[0].AxisY.ScrollBar.Enabled = true;
        chart_TimeChart.Series[series_timeneeded].BorderWidth = 2;
        chart_TimeChart.Series[series_timeneeded].ChartType = SeriesChartType.StackedBar; 
        chart_TimeChart.Series[series_timeneeded].YValueType = ChartValueType.Time;
        chart_TimeChart.ChartAreas[0].AxisY.LabelStyle.Format = "HH:mm:ss";
        chart_TimeChart.Series[series_timeneeded].XValueType = ChartValueType.String;

            for (int i = 0; i < MaxNumber; i++) 
                {
                    chart_TimeChart.Series[series_timeneeded].Points.AddXY("item"+ " " + (i + 1).ToString(), DateTime.Now.Add(Timespans[i]));
                }

        chart_TimeChart.Series.Add(series_FinishTime);
        chart_TimeChart.Series[series_FinishTime].ChartType = SeriesChartType.StackedBar;
        chart_TimeChart.Series[series_FinishTime].BorderWidth = 0;
        chart_TimeChart.Series[series_FinishTime].MarkerSize = 15;
        chart_TimeChart.Series[series_FinishTime].MarkerStyle = MarkerStyle.Square;
        chart_TimeChart.Series[series_FinishTime].MarkerColor = Color.Black;

        chart_TimeChart.Series[series_FinishTime].YValueType = ChartValueType.DateTime;
        chart_TimeChart.Series[series_FinishTime].XValueType = ChartValueType.String;

        for (int i = 0; i < MaxNumber; i++) 
                {
                    DateTime YPosition = GetFinishTime(i);

                    chart_TimeChart.Series[series_FinishTime].Points.AddXY("item"+ " " +(i+1).ToString(), YPosition);
                }
代码将显示为:

但我希望它看起来像这样:

aSeries["DrawSideBySide"] = "false";
aSeries.SetCustomProperty("DrawSideBySide", "false");

!!请参阅下面的更新


如果确实要创建堆叠条形图,则图表有两个问题:

  • 如果要堆叠数据点,它们需要有有意义的x值;如果没有它们,它怎么知道彼此要叠加什么呢
您添加了字符串,这些字符串看起来不错,但根本不起作用。这是因为
DataPoint.XValue
字段是
double
,当您向其中添加
string
时,它被设置为
0
!!您的字符串将复制到
标签
,但在其他情况下会丢失

因此,您需要
为x值提供合适的数值

  • 您还需要对要堆叠的序列进行分组。为此,有一个名为
    StackedGroupName
    的特殊属性,用于对应堆叠的序列进行分组
以下是如何使用它:

yourSeries1.SetCustomProperty("StackedGroupName", "Group1");
有关完整示例,请参见

它还显示了一种使用您选择的字符串值设置标签的方法

这是制作真正的
StackedBar
图表的方法。您的变通方法可能有效,也可能无效。您可以尝试使颜色透明或与图表的底色相等;但在我看来,这只不过是一次黑客攻击


更新

我想我误解了这个问题。从我看到的情况来看,您并不是真的想要创建堆叠图表

相反,你要努力解决这些问题:

  • 在同一y点显示条形图
  • 让一些酒吧隐形
  • 将垂直线显示为标记
让我们逐一解决:

  • 一些列类型包括所有
    ,然后一些列具有一个鲜为人知的特殊属性
默认情况下,设置为
Auto
,其工作方式类似于
True
。这通常是很好的,因为我们不希望条形图相互重叠,从而有效地隐藏所有或部分重叠点

但这里我们确实希望它们共享相同的y位置,因此我们需要为至少一个
系列
将属性设置为
false
;其他(在
Auto
上)将跟随..:

您可以这样做:

aSeries["DrawSideBySide"] = "false";
aSeries.SetCustomProperty("DrawSideBySide", "false");
或者像这样:

aSeries["DrawSideBySide"] = "false";
aSeries.SetCustomProperty("DrawSideBySide", "false");

  • 接下来,我们隐藏覆盖的
    系列
    ;这很简单:

  • 最后一个问题是显示线标记。没有这样的样式,所以我们需要使用自定义样式。为此,我们需要创建一个合适的位图,并将其添加到图表的
    Images
    集合中
这听起来比实际情况更复杂;但是,
MarkerImage
不会被缩放,因此我们需要在调整图表大小或添加/删除点时创建合适的大小。我暂时不考虑这个复杂问题

int pointCount = 10;
Bitmap bmp = new Bitmap(2, chart.ClientSize.Height / pointCount - 5);
using (Graphics g = Graphics.FromImage(bmp)) g.Clear(Color.Black);
NamedImage marker = new NamedImage("marker", bmp);
chart.Images.Clear();  // quick & dirty
chart.Images.Add(marker);
结果如下:

请注意:

  • 我建议对重复引用的所有图表元素使用变量,而不是一直使用索引引用。代码更少,更易于阅读,更易于维护,而且性能可能更好

  • 由于代码要求可见数据点为红色或绿色,
    图例
    将不会显示良好的表示。有关绘制多色图例项的示例,请参见

  • 我使用图表高度;不建议这样做,因为可能有
    标题
    图例
    或更多
    图表区
    ;相反,您应该使用
    图表区域的高度,或者更精确地说,使用
    内部绘图位置的高度。您需要将这些从百分比转换为像素。不要太用力,请看下面或下面
    或者更多的例子

  • 标记应根据
    调整大小
    以及可能来自
    AxisViewChanged
    事件进行调整。将它放在一个好的函数中调用(例如,
    void setMarkerImage(图表、系列s、字符串名称、整数宽度、颜色c)
    )总是一个好主意

  • 如果需要反复调整标记图像的大小,可能需要编写更好的代码来清除旧标记图像;这应该包括处理以前使用的
    位图

以下是一个例子:

var oldni = chart.Images.FindByName("marker");
if (oldni != null)
{
    oldni.Image.Dispose();
    chart.Images.Remove(oldni);
    oldni.Dispose();
}
  • 在某些情况下,需要轻推图表以更新其某些属性
    RecreacteAxesCale
    就是这样一种轻推
计算适当标记高度的示例:

ChartArea ca = chart.ChartAreas[0];
ca.RecalculateAxesScale();
float cah = ca.Position.Height;
float iph = ca.InnerPlotPosition.Height;
float h = chart3.ClientSize.Height * cah / 100f * iph / 100f;
int mh = (int)(h / s.Points.Count);
  • 最后一点:原始答案强调了使用有意义的x值的重要性。弦是无用的!这对于堆放钢筋非常重要;但现在,当我们希望酒吧坐在相同的垂直位置时,这同样重要!将x值添加为字符串再次导致无意义

(因为我们有
x值沿纵轴移动,反之亦然。)

顺便说一句。我尝试了“chart\u TimeChart.Series[Series\u FinishTime][“PixelPointWidth”]”0"; 但显然这不起作用,因为我无法将宽度设置为零。请查看更新后的答案。我一开始误解了你的问题,对不起!您仍然将charttype设置为stackedbars。我不认为这是你真正想要的。您仍然可以将x值添加为字符串。不过,你需要数字。你需要想出一个方案,使用简单的数字将点分组到各自的插槽中。您好,很抱歉