LiveCharts2 Documentation

repository·master·Indexed 26 days ago

https://github.com/live-charts/livecharts2

A flexible, cross-platform data visualization library for .NET. Supports multiple UI frameworks including MAUI, Uno Platform, WPF, WinUI, Xamarin.Forms, WindowsForms, BlazorWasm, Avalonia, Eto Forms, and UWP. Includes the lvc CLI tool for rendering charts in the terminal via JSON specifications, support for MVVM patterns, and extensive configuration for Cartesian charts, including zooming, panning, and axis customization.

Tokens
46.8K
Snippets
134
Records
233
Agent score
90%

What's inside LiveCharts2

  1. Use Paints for graphical rendering

    master

    A Paint is an object used to render graphical elements in the UI, similar to Brushes in WPF or AvaloniaUI. LiveCharts2 uses a wrapper around SkiaSharp's Paint that adds features like animations and a more developer-friendly API.

    You can assign a paint to various properties to control rendering:

    • Series: Fill and Stroke properties.
    • Axes: DataLabelsPaint and SeparatorPaint properties.

    Setting a paint to null is valid and means the visual will be ignored or not drawn.

  2. Understand the LiveCharts2 Architecture

    master

    LiveCharts2 is composed of three main modules that work together to render charts:

    • Core: Defines the API for shapes and generates the geometries and sizes required for a chart.
    • Renderer: Consumes the Core API to materialize geometries into images using SkiaSharp.
    • View: The UI component that coordinates between the Core (asking what to draw) and the Renderer (asking how to draw it).

    Animations are handled by the Core using IAnimatable objects and MotionProperty definitions. When a property is set, it schedules a value over a timeline rather than applying it instantly.

  3. Draw custom shapes directly on the canvas

    master

    You can draw custom shapes or effects directly on the canvas using the SkiaSharp API. This is achieved by overriding the OnDraw method in a class that inherits from Geometry.

    Implementation Steps:

    1. Inherit from Geometry: Use the Geometry class to access properties for location, rotation, opacity, or transforms.
    2. Override OnDraw: Define your drawing logic inside this method.
    3. Use MotionProperty<T>: For properties that should animate (like position or size), use the MotionProperty<T> type. When accessed, it returns the value at the current point in the animation timeline.
    4. Define Paints: Create an instance of SolidColorPaint to define how the geometry is rendered (e.g., color, stroke width).
    5. Register with Canvas: Add your geometries to the paint, and then add the paint to the canvas.

    Important Lifecycle Note:

    LiveCharts uses a MotionCanvas that redraws the UI (approximately 60 times per second) until all animations complete. Only perform drawing operations inside the OnDraw method; do not perform heavy logic or scheduling there.

  4. Handle multi-threading concurrency hazards in LiveCharts2

    master

    When updating chart data from background threads, you may encounter InvalidOperationException (Collection Was Modified) or other synchronization errors because the chart might attempt to measure data while it is being modified.

    To prevent these concurrency hazards, you must use one of two strategies:

    1. Locking changes: Use a synchronization object to wrap data changes and inform the chart of this object.
    2. UI Thread Invocation: Force all data changes to occur on the UI thread.

    Alternative 1: Locking changes

    Use the C# lock keyword to wrap any modifications to your data collection. To ensure the chart respects this lock during its measurement phase, you must assign your synchronization object to the chart's SyncContext property.

    Alternative 2: Invoke changes on the UI thread

    Perform all data updates on the same thread used by the UI. This eliminates concurrency hazards by ensuring all operations happen sequentially on a single thread, though it increases the workload on the UI thread.

  5. Render charts as images in server-side or console applications

    master

    LiveCharts2 can render charts as images without requiring a UI framework (like WPF, WinForms, or MAUI). This is useful for server-side image generation or console applications. To use this capability, you must install the LiveChartsCore.SkiaSharpView NuGet package.

    If you are already using LiveCharts to render UI controls in a framework like WPF or WinForms, you already have this dependency and do not need to install it again.

  6. Configure a Console Application for image rendering

    master

    To build images in a console application:

    1. Create a new Console Application in Visual Studio 2022.
    2. Select .NET 6.0 as the target framework (LiveCharts2 also supports .NET 5.0, .NET Core 3.1, or .NET Framework 4.6.2 or greater).
    3. Install the LiveChartsCore.SkiaSharpView package.
    4. Use the SkiaSharp-based rendering logic in your Program.cs to generate images of charts such as CartesianChart, PieChart, or GeoMap.
  7. Use RangeColumnSeries for waterfall or error-range charts

    master

    The RangeColumnSeries<TModel> draws vertical rectangles spanning a [Low, High] range on the value axis. This is ideal for waterfall charts, error-range columns, or any visualization where a metric occupies a specific interval rather than growing from a single pivot point.

    The simplest way to implement this is using the RangeValue helper from LiveChartsCore.Defaults, which automatically maps Low and High to the required coordinate slots (PrimaryValue = High, TertiaryValue = Low).

    Series = new ISeries[]
    {
        new RangeColumnSeries<RangeValue>
        {
            Values = new []
            {
                new RangeValue(0,  100),   // Start balance — anchored at 0
                new RangeValue(100, 150),  // Sales            (+50)
                new RangeValue(150, 180),  // Other income     (+30)
                new RangeValue(180, 130),  // Costs            (−50)
                new RangeValue(130, 110),  // Tax              (−20)
                new RangeValue(0,  110),   // End balance      — anchored at 0
            }
        }
    };
  8. Use the GeoMap control for geographical maps

    master

    The GeoMap control renders vectorized maps using GeoJSON files. To create a heat map, use HeatLandSeries and provide a collection of HeatLand objects. Each HeatLand requires a Name (which corresponds to the shortName property in your GeoJSON file) and a Value.

    // Example for XAML/Blazor/WinForms logic
    public HeatLandSeries[] Series { get; set; } = new HeatLandSeries[]
    {
        new HeatLandSeries
        {
            Lands = new HeatLand[]
            {
                new HeatLand { Name = "bra", Value = 13 },
                new HeatLand { Name = "mex", Value = 10 },
                new HeatLand { Name = "usa", Value = 15 }
            }
        }
    };
  9. Create a custom tooltip implementation

    master

    If the default tooltip styling is insufficient, you have two main options:

    1. Inherit from SKDefaultTooltip: Override specific parts of the default SkiaSharp tooltip to change its behavior or appearance (e.g., drawing custom geometry based on the active point).
    2. Implement IChartTooltip: Create a tooltip from scratch. You can use the LiveCharts API to draw within control bounds or use your specific UI framework's native tooltip capabilities. Any class implementing IChartTooltip can be used as a tooltip.
  10. Configure DateTime Axis for Financial Charts

    master

    When using FinancialPoint with a DateTime axis, you should configure the Axis to handle time intervals correctly using UnitWidth. This ensures the spacing between points reflects the actual time elapsed (e.g., days).

    To set the unit width to days, use TimeSpan.FromDays(1).Ticks.

    XAxes = new[]
    {
        new Axis
        {
            LabelsRotation = 15,
            Labeler = value => new DateTime((long)value).ToString("yyyy MMM dd"),
            // set the unit width of the axis to "days"
            UnitWidth = TimeSpan.FromDays(1).Ticks
        }
    };