Python如何绘制饼图:绘制饼图(drawing of pie)

在看了几个创建 piphart 的例子之后,我做了以下UserControl

public partial class PieChart : UserControl
{
    #region DependencyProperties
    public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(PieChart), new PropertyMetadata(0d));
    public static readonly DependencyProperty SeriesProperty = DependencyProperty.Register("Series", typeof(List<PieSeries>), typeof(PieChart), new PropertyMetadata(null, Draw));
    public double Radius {
        get { return (double)GetValue(RadiusProperty); }
        set { SetValue(RadiusProperty, value); }
    }
    public List<PieSeries> Series {
        get { return (List<PieSeries>)GetValue(SeriesProperty); }
        set { SetValue(SeriesProperty, value); }
    }
    static void Draw(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as PieChart;
        control.AddPie(control.chartArea);
    }
    #endregion
    Brush[] colors = new Brush[] { Brushes.Gray, Brushes.Green, Brushes.Blue, Brushes.LightGray, Brushes.AntiqueWhite };
    double xCenter, yCenter;
    public PieChart()
    {
        InitializeComponent();
    }
    void AddPie(Canvas canvas)
    {
        canvas.Width = 300; canvas.Height = 300;
        xCenter = canvas.Width / 2;
        yCenter = canvas.Height / 2;
        double sum, startAngle, sweepAngle;
        sum = Series.Sum(x => x.Value);
        startAngle = sweepAngle = 0.0;
        for (int i = 0; i < Series.Count; i++)
        {
            var brush = colors[i];
            startAngle += sweepAngle;
            sweepAngle = 2 * Math.PI * Series[i].Value / sum;
            DrawSegments(canvas, brush, startAngle, startAngle + sweepAngle);
        }
    }
    void DrawSegments(Canvas canvas, Brush fillColor, double startAngle, double endAngle)
    {
        var line1 = new LineSegment() { Point = new Point(xCenter + Radius * Math.Cos(startAngle), yCenter + Radius * Math.Sin(startAngle)) };
        var line2 = new LineSegment() { Point = new Point(xCenter + Radius * Math.Cos(endAngle), yCenter + Radius * Math.Sin(endAngle)) };
        var arc = new ArcSegment()
        {
            SweepDirection = SweepDirection.Clockwise,
            Size = new Size(Radius, Radius),
            Point = new Point(xCenter + Radius * Math.Cos(endAngle), yCenter + Radius * Math.Sin(endAngle))
        };
        var figure = new PathFigure() { IsClosed = true, StartPoint = new Point(xCenter, yCenter), Segments = { line1, arc, line2 } };
        var geometry = new PathGeometry() { Figures = { figure } };
        var path = new Path() { Fill = fillColor, Data = geometry };
        canvas.Children.Add(path);
    }
}

xaml中:

<UserControl ...>
<Grid>
        <Canvas x:Name="chartArea" Margin="10"/>
    </Grid>
</UserControl>

不确定这是否是正确的方法,但它有效。问题在于AddPie方法。我必须设置CanvasWidthHeight,否则MainWindow中不会显示任何内容。下面是我在MainWindow中使用它的方式:

<Window>
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <local:PieChart Grid.Row="1"
                        Radius="100"
                        Series="{Binding Series}"/>
    </Grid>
</Window>

在 ViewModel 的constructor中,我创建了Series

Series = new List<PieSeries>()
{
    new PieSeries("A", 30),
    new PieSeries("B", 20),
    new PieSeries("C", 10),
    new PieSeries("D", 15),
    new PieSeries("E", 25)
};

Draw回调中,我总是得到0作为ActualHeightActualWidthCanvas,命名为chartArea,所以当我调整窗口大小时,馅饼不会自动调整大小!

如何解决这个问题?

有没有更好的方法来绘制简单的饼图?在我的情况下List<PieSeries>可能有 1 项到 5 项。

EDIT

使用注释中建议的方法,它更简单!在我的 ViewModel,VM,我有这些:

public class VM : INotifyPropertyChanged
{
    public ObservableCollection<ShapeData> Series { get; set; } = new ObservableCollection<ShapeData>();
    double[] array = { 30, 10, 15, 20, 25};
    Brush[] brushes = new Brush[] { Brushes.Gray, Brushes.Green, Brushes.Blue, Brushes.LightGray, Brushes.AntiqueWhite };
    double radius, xCenter, yCenter;
    public Command Resized { get; set; }
    public VM()
    {
        radius = 100;
        Resized = new Command(resized, (o) => true);
    }
    void resized(object obj)
    {
        var canvas = obj as Canvas;
        xCenter = canvas.ActualWidth / 2;
        yCenter = canvas.ActualHeight / 2;
        Series.Clear();
        DrawPie(array, brushes, radius);
    }
    void DrawPie(double[] values, Brush[] colors, double radius)
    {
        var sum = values.Sum();
        double startAngle, sweepAngle;
        startAngle = sweepAngle = 0;
        for (int i = 0; i < values.Length; i++)
        {
            startAngle += sweepAngle;
            sweepAngle = 2 * Math.PI * values[i] / sum;
            var line1 = new LineSegment() { Point = new Point(xCenter + radius * Math.Cos(startAngle), yCenter + radius * Math.Sin(startAngle)) };
            var line2 = new LineSegment() { Point = new Point(xCenter + radius * Math.Cos(startAngle + sweepAngle), yCenter + radius * Math.Sin(startAngle + sweepAngle)) };
            var arc = new ArcSegment()
            {
                SweepDirection = SweepDirection.Clockwise,
                Size = new Size(radius, radius),
                Point = new Point(xCenter + radius * Math.Cos(startAngle + sweepAngle), yCenter + radius * Math.Sin(startAngle + sweepAngle))
            };
            var figure = new PathFigure() { IsClosed = true, StartPoint = new Point(xCenter, yCenter), Segments = { line1, arc, line2 } };
            Series.Add(new ShapeData()
            {
                Geometry = new PathGeometry() { Figures = { figure } },
                Fill = colors[i],
                Stroke = Brushes.Red,
                StrokeThickness = 1
            });
        }
    }
    #region Notify Property Changed Members
    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    #endregion
}
and inxaml:
<ItemsControl Grid.Row="1" ItemsSource="{Binding Series}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Path Data="{Binding Geometry}"
                    Fill="{Binding Fill}"
                    Stroke="{Binding Stroke}"
                    StrokeThickness="{Binding StrokeThickness}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas x:Name="panel">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SizeChanged">
                        <i:InvokeCommandAction Command="{Binding Resized}"
                                                CommandParameter="{Binding ElementName=panel}"/>
                    </i:EventTrigger>
                    <i:EventTrigger EventName="Loaded">
                        <i:InvokeCommandAction Command="{Binding Resized}"
                                                CommandParameter="{Binding ElementName=panel}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Canvas>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

xaml中,我在<ItemsPanelTemplate>标签上收到警告

未找到类型“System.Windows.Interactivity.TriggerCollection”的默认构造函数。可以使用 Arguments 或 FactoryMethod 指令构造此类型。

本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处

(152)
高级情侣cp昵称符号:使用保留父结构的 cp创建符号链接
上一篇
葡萄牙c罗个人简历:葡萄牙语编码(is 7 8 in portuguese)
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(61条)