绘制柱形图,柱与柱之间没有空间

发布于 2024-08-31 05:51:28 字数 1272 浏览 6 评论 0原文

我正在使用 WPF 工具包,并尝试渲染一个看起来像直方图的图形。特别是,我希望每一列都与其他列相对应。列之间不应有间隙。

创建柱形图时需要应用许多组件。 (请参阅下面的示例 XAML)。有谁知道是否可以在其中一个元素上设置一个属性,该属性指的是列之间的空白宽度?

                <charting:Chart Height="600" Width="Auto" HorizontalAlignment="Stretch" Name="MyChart"
                    Title="Column Graph" LegendTitle="Legend">

                    <charting:ColumnSeries 
                        Name="theColumnSeries"
                        Title="Series A"
                        IndependentValueBinding="{Binding Path=Name}"                
                        DependentValueBinding="{Binding Path=Population}"
                        Margin="0"
                        >
                    </charting:ColumnSeries>

                    <charting:Chart.Axes>
                        <charting:LinearAxis 
                            Orientation="Y" 
                            Minimum="200000" 
                            Maximum="2500000" 
                            ShowGridLines="True" />
                        <charting:CategoryAxis
                            Name="chartCategoryAxis"
                            />
                    </charting:Chart.Axes>
                </charting:Chart>

I am using the WPF toolkit, and am trying to render a graph that looks like a histogram. In particular, I want each column to be right up against each other column. There should be no gaps between columns.

There are a number of components that you apply when creating a column graph. (See example XAML below). Does anybody know if there is a property you can set on one of the elements which refers to the width of the white space between columns?

                <charting:Chart Height="600" Width="Auto" HorizontalAlignment="Stretch" Name="MyChart"
                    Title="Column Graph" LegendTitle="Legend">

                    <charting:ColumnSeries 
                        Name="theColumnSeries"
                        Title="Series A"
                        IndependentValueBinding="{Binding Path=Name}"                
                        DependentValueBinding="{Binding Path=Population}"
                        Margin="0"
                        >
                    </charting:ColumnSeries>

                    <charting:Chart.Axes>
                        <charting:LinearAxis 
                            Orientation="Y" 
                            Minimum="200000" 
                            Maximum="2500000" 
                            ShowGridLines="True" />
                        <charting:CategoryAxis
                            Name="chartCategoryAxis"
                            />
                    </charting:Chart.Axes>
                </charting:Chart>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

2024-09-07 05:51:28

由于没有神奇的答案,我从 codeplex 下载了 wpftoolkit 代码。

通过阅读代码,我可以看到在方法 ColumnSeries.UpdateDataPoint 中,有这样一行代码:

    double segmentWidth = coordinateRangeWidth * 0.8;

所以这是一个非常明确的“不”,您不能通过设置 public 来更改列之间的间隙财产。

我要尝试的解决方案是编写一个继承自ColumnSeries的新类,并重写UpdateDataPoint


稍后编辑

好的,我开始工作了。如果有人感兴趣,我附上了 HistogramSeries 类的完整代码。

public class HistogramSeries : ColumnSeries, ISeries
{
    protected override void UpdateDataPoint(DataPoint dataPoint)
    {
        // That set the height and width.
        base.UpdateDataPoint(dataPoint);
        // Now we override the part about setting the width
        object category = dataPoint.ActualIndependentValue;
        var coordinateRange = GetCategoryRange(category);
        double minimum = (double)coordinateRange.Minimum.Value;
        double maximum = (double)coordinateRange.Maximum.Value;
        double coordinateRangeWidth = (maximum - minimum);
        const int WIDTH_MULTIPLIER = 1; // Harcoded to 0.8 in the parent. Could make this a dependency property
        double segmentWidth = coordinateRangeWidth * WIDTH_MULTIPLIER;
        var columnSeries = SeriesHost.Series.OfType<ColumnSeries>().Where(series => series.ActualIndependentAxis == ActualIndependentAxis);
        int numberOfSeries = columnSeries.Count();
        double columnWidth = segmentWidth / numberOfSeries;
        int seriesIndex = columnSeries.IndexOf(this);
        double offset = seriesIndex * Math.Round(columnWidth) + coordinateRangeWidth * 0.1;
        double dataPointX = minimum + offset;
        double left = Math.Round(dataPointX);
        double width = Math.Round(columnWidth);
        Canvas.SetLeft(dataPoint, left);
        dataPoint.Width = width;
    }
    #region ISeries Members
    System.Collections.ObjectModel.ObservableCollection<object> ISeries.LegendItems
    {
        get { return base.LegendItems; }
    }
    #endregion
    #region IRequireSeriesHost Members
    ISeriesHost IRequireSeriesHost.SeriesHost
    {
        get { return base.SeriesHost;}
        set { base.SeriesHost = value; }
    }
    #endregion
}
// Copied from the DataVisualization library
// (It was an internal class)
static class MyEnumerableFunctions
{
    public static int IndexOf(this IEnumerable that, object value)
    {
        int index = 0;
        foreach (object item in that)
        {
            if (object.ReferenceEquals(value, item) || value.Equals(item))
            {
                return index;
            }
            index++;
        }
        return -1;
    }
}

In the absence of magically-appearing answers, I downloaded the wpftoolkit code from codeplex.

By reading the code, I can see in the method ColumnSeries.UpdateDataPoint, there is this line of code:

    double segmentWidth = coordinateRangeWidth * 0.8;

So that's a pretty definitive "no", you cannot change the gap in between columns by setting a public property.

The solution which I'm going to try is to write a new class that inherits from ColumnSeries, and overriding UpdateDataPoint.


Later Edit

OK, I got it to work. In case anyone's interested, I've attached the full code for the HistogramSeries class.

public class HistogramSeries : ColumnSeries, ISeries
{
    protected override void UpdateDataPoint(DataPoint dataPoint)
    {
        // That set the height and width.
        base.UpdateDataPoint(dataPoint);
        // Now we override the part about setting the width
        object category = dataPoint.ActualIndependentValue;
        var coordinateRange = GetCategoryRange(category);
        double minimum = (double)coordinateRange.Minimum.Value;
        double maximum = (double)coordinateRange.Maximum.Value;
        double coordinateRangeWidth = (maximum - minimum);
        const int WIDTH_MULTIPLIER = 1; // Harcoded to 0.8 in the parent. Could make this a dependency property
        double segmentWidth = coordinateRangeWidth * WIDTH_MULTIPLIER;
        var columnSeries = SeriesHost.Series.OfType<ColumnSeries>().Where(series => series.ActualIndependentAxis == ActualIndependentAxis);
        int numberOfSeries = columnSeries.Count();
        double columnWidth = segmentWidth / numberOfSeries;
        int seriesIndex = columnSeries.IndexOf(this);
        double offset = seriesIndex * Math.Round(columnWidth) + coordinateRangeWidth * 0.1;
        double dataPointX = minimum + offset;
        double left = Math.Round(dataPointX);
        double width = Math.Round(columnWidth);
        Canvas.SetLeft(dataPoint, left);
        dataPoint.Width = width;
    }
    #region ISeries Members
    System.Collections.ObjectModel.ObservableCollection<object> ISeries.LegendItems
    {
        get { return base.LegendItems; }
    }
    #endregion
    #region IRequireSeriesHost Members
    ISeriesHost IRequireSeriesHost.SeriesHost
    {
        get { return base.SeriesHost;}
        set { base.SeriesHost = value; }
    }
    #endregion
}
// Copied from the DataVisualization library
// (It was an internal class)
static class MyEnumerableFunctions
{
    public static int IndexOf(this IEnumerable that, object value)
    {
        int index = 0;
        foreach (object item in that)
        {
            if (object.ReferenceEquals(value, item) || value.Equals(item))
            {
                return index;
            }
            index++;
        }
        return -1;
    }
}
何以笙箫默 2024-09-07 05:51:28

感谢代码示例。这几乎正​​是我所需要的。我将其翻译成VB.Net并删除了小部分。

Imports System.Windows.Controls.DataVisualization.Charting


Public Class HistogramSeries
    Inherits ColumnSeries

    Protected Overrides Sub UpdateDataPoint(dataPoint As DataPoint)
        MyBase.UpdateDataPoint(dataPoint)

    ' Now we override the part about setting the width
        Dim category As Object = dataPoint.ActualIndependentValue
        Dim coordinateRange = GetCategoryRange(category)
        Dim minimum As Double = CDbl(coordinateRange.Minimum.Value)
        Dim maximum As Double = CDbl(coordinateRange.Maximum.Value)
        Dim coordinateRangeWidth As Double = (maximum - minimum)
        Const WIDTH_MULTIPLIER As Integer = 1 ' Harcoded to 0.8 in the parent. Could make this a dependency property
        Dim segmentWidth As Double = coordinateRangeWidth * WIDTH_MULTIPLIER
        Dim columnS As System.Collections.Generic.IEnumerable(Of ColumnSeries) = SeriesHost.Series.OfType(Of ColumnSeries)().Where(Function(series) series.ActualIndependentAxis Is ActualIndependentAxis)
        Dim numberOfSeries As Integer = columnS.Count
        Dim columnWidth As Double = segmentWidth / numberOfSeries
        Dim seriesIndex As Integer = columnS.ToList.IndexOf(Me)
        Dim offset As Double = seriesIndex * Math.Round(columnWidth) + coordinateRangeWidth * 0.1
        Dim dataPointX As Double = minimum + offset
        Dim left As Double = Math.Round(dataPointX)
        Dim width As Double = Math.Round(columnWidth)
        Canvas.SetLeft(dataPoint, left)
        dataPoint.Width = width
    End Sub

End Class

Thx for the code example. It was almost exactly what I have needed. I translated it into VB.Net and erased the minor parts.

Imports System.Windows.Controls.DataVisualization.Charting


Public Class HistogramSeries
    Inherits ColumnSeries

    Protected Overrides Sub UpdateDataPoint(dataPoint As DataPoint)
        MyBase.UpdateDataPoint(dataPoint)

    ' Now we override the part about setting the width
        Dim category As Object = dataPoint.ActualIndependentValue
        Dim coordinateRange = GetCategoryRange(category)
        Dim minimum As Double = CDbl(coordinateRange.Minimum.Value)
        Dim maximum As Double = CDbl(coordinateRange.Maximum.Value)
        Dim coordinateRangeWidth As Double = (maximum - minimum)
        Const WIDTH_MULTIPLIER As Integer = 1 ' Harcoded to 0.8 in the parent. Could make this a dependency property
        Dim segmentWidth As Double = coordinateRangeWidth * WIDTH_MULTIPLIER
        Dim columnS As System.Collections.Generic.IEnumerable(Of ColumnSeries) = SeriesHost.Series.OfType(Of ColumnSeries)().Where(Function(series) series.ActualIndependentAxis Is ActualIndependentAxis)
        Dim numberOfSeries As Integer = columnS.Count
        Dim columnWidth As Double = segmentWidth / numberOfSeries
        Dim seriesIndex As Integer = columnS.ToList.IndexOf(Me)
        Dim offset As Double = seriesIndex * Math.Round(columnWidth) + coordinateRangeWidth * 0.1
        Dim dataPointX As Double = minimum + offset
        Dim left As Double = Math.Round(dataPointX)
        Dim width As Double = Math.Round(columnWidth)
        Canvas.SetLeft(dataPoint, left)
        dataPoint.Width = width
    End Sub

End Class
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文