ProEssentials Data Handling

Master Your Chart Data Architecture

data point
chart symbol
charting symbol
scientific chart
chart data
data arrays
chart memory
data symbol

Understanding ProEssentials
Data Architecture & Best Practices

The ProEssentials Data Philosophy

ProEssentials is a native C/C++ component that renders directly via Direct2D, Direct3D, and GDI+ to a Windows device context. This low-level architecture means data handling follows classic C/C++ and C# basic array patterns: simple contiguous blocks of memory; reducing the number of such block.

Managing Data in Your Application

Gigasoft strongly recommends that you maintain your data in standard arrays within your application before passing or (passing Reference) to ProEssentials. This approach provides several benefits:

  • Clarity - Your data exists in a known, inspectable location
  • Debugging - You can examine array contents directly in the debugger
  • AI Compatibility - ChatGPT, Claude, Copilot excel at manipulating standard arrays
  • Flexibility - Process, filter, or transform data before charting
  • Reusability - Share the same data across multiple charts. The ProEssentials product installs a demo called GigaPrime3D that demonstrates data reuse between 3 charts—literally the simplest and most impressive demo of data reusability. It also demonstrates the world's fastest GPU-side ComputeShader rendering of this reused data. Run GigaPrime3D and see for yourself; then study the small amount of simple code and memory this demo requires.

Understanding Subsets and Points

ProEssentials organizes chart data using two fundamental dimensions: Subsets and Points.

  • Subsets - Think of these as rows or data series. In a line chart, each subset is a separate line with its own color.
  • Points - Think of these as columns or data values per series. Each point represents one value along the x-axis.

For example, a chart with 4 temperature sensors recording 1000 measurements each would have:Subsets = 4 and Points = 1000.

Important Note for Non-Jagged Data

When using the default Non-Jagged mode (JaggedData = false), always set PeData.Subsets and PeData.Points BEFORE passing any data to the chart, as this defines the single contiguous memory block size.

How ProEssentials Stores Data Internally

ProEssentials offers two internal storage modes, controlled by the JaggedData property:

Non-Jagged Data (Default)

JaggedData = false (Default)

All data is stored in one contiguous block of memory. Every subset has the same number of points.

// Memory layout: One flat array
// Size = Subsets × Points
float[48] = 4 subsets × 12 points

// Access formula (SubsetByPoint=true):
index = (nSubsetIndex × Points) + nPointIndex

Best for: Regular datasets where all series have identical sample counts. This covers 98% of charting use cases and is the most efficient mode.

Jagged Data

JaggedData = true

Each subset is stored as a separate block of memory. Subsets can have different numbers of points.

// Memory layout: Array of arrays
Subset[0] → float[12000] points
Subset[1] → float[1200] points
Subset[2] → float[120] points
Subset[3] → float[12] points

Best for: Sensors with different sample rates, datasets with varying lengths, or when combining data from different sources. Currently requires RenderEngine = Direct2D.

Recommendation: Use Non-Jagged (default) mode unless your subsets genuinely have different point counts. Non-Jagged is faster and supported by all RenderEngines including Direct3D with optional ComputeShader GPU side construction and CircularBuffers.

Data Passing Methods

ProEssentials provides multiple ways to transfer data from your application to the chart. Each method has specific strengths depending on your data size and use case.

1. Direct Indexer (Spoon Feeding)

Set individual values one at a time using the indexer syntax.

// C# .NET - Spoon feeding individual values
Pesgo1.PeData.Subsets = 4;
Pesgo1.PeData.Points = 12;

for (int s = 0; s <= 3; s++)
{
    for (int p = 0; p <= 11; p++)
    {
        Pesgo1.PeData.X[s, p] = (float)(p + 1);
        Pesgo1.PeData.Y[s, p] = (float)(Rand_Num.NextDouble() * 100);
    }
}
Pesgo1.PeFunction.ReinitializeResetImage();

Performance: Slower than block methods, but ProEssentials is native code so this is still quite efficient
Best for: Datasets up to ~100,000 total points, quick prototyping, or when you need to set sparse values

2. FastCopyFrom (.NET)

Block copy entire arrays to the chart. FastCopyFrom internally calls PEvset which uses memcpy for maximum speed.

// C# .NET - Block copy with FastCopyFrom
Pesgo1.PeData.Subsets = 4;
Pesgo1.PeData.Points = 12;

float[] MyXData = new float[48]; // 4 × 12 = 48
float[] MyYData = new float[48];

for (int s = 0; s <= 3; s++)
{
    for (int p = 0; p <= 11; p++)
    {
        int o = (s * 12) + p;
        MyXData[o] = (float)(p + 1);
        MyYData[o] = (float)(Rand_Num.NextDouble() * 100);
    }
}
Pesgo1.PeData.X.FastCopyFrom(MyXData);
Pesgo1.PeData.Y.FastCopyFrom(MyYData);
Pesgo1.PeFunction.ReinitializeResetImage();

Performance: Fastest .NET method - uses memcpy internally
Best for: Large datasets (100K to 500K points), performance-critical applications
Note: if data is less than 100K bytes, pin the memory, as is the case for all data methods belowWrapper: FastCopyFrom wraps the PEvsetW DLL function

3. FastCopyFromJagged (.NET)

For JaggedData mode, copy individual subsets from C# jagged arrays (arrays of arrays).

// C# .NET - Jagged data, each subset has its own array
Pesgo1.PeData.JaggedData = true;
Pesgo1.PeData.Subsets = 4;
Pesgo1.PeData.Points = 1;

float[][] MyXData = new float[4][];
float[][] MyYData = new float[4][];

for (int s = 0; s <= 3; s++)
{
    MyXData[s] = new float[12];
    MyYData[s] = new float[12];
    for (int p = 0; p <= 11; p++)
    {
        MyXData[s][p] = (float)(p + 1);
        MyYData[s][p] = (float)(Rand_Num.NextDouble() * 100);
    }
    Pesgo1.PeData.X.FastCopyFromJagged(MyXData[s], s);
    Pesgo1.PeData.Y.FastCopyFromJagged(MyYData[s], s);
}
Pesgo1.PeFunction.ReinitializeResetImage();

Performance: Fast per-subset copying
Best for: Datasets where subsets have different sample counts
Wrapper: FastCopyFromJagged wraps PEvsetEx DLL function

4. UseDataAtLocation (Zero-Copy Reference)

Instead of copying data to the chart, tell ProEssentials where your data already exists. The chart reads directly from your memory - no copy overhead.

// C# .NET - Zero-copy via UseDataAtLocation
// Arrays must persist — use static, class-level, or MainWindow scope
static float[] MyXData = new float[48]; // 4 × 12 = 48
static float[] MyYData = new float[48];

for (int s = 0; s <= 3; s++)
{
    for (int p = 0; p <= 11; p++)
    {
        int o = (s * 12) + p;
        MyXData[o] = (float)(p + 1);
        MyYData[o] = (float)(Rand_Num.NextDouble() * 100);
    }
}

Pesgo1.PeData.Subsets = 4;
Pesgo1.PeData.Points = 12;
Pesgo1.PeData.X.UseDataAtLocation(MyXData, 48);
Pesgo1.PeData.Y.UseDataAtLocation(MyYData, 48);
Pesgo1.PeFunction.ReinitializeResetImage();

// To clear: call with no arguments
// Pesgo1.PeData.X.UseDataAtLocation();

Performance: Zero copy overhead - chart uses your memory directly
Best for: Datasets >500K points, multiple charts sharing same data, real-time updates
Requirement: Arrays must remain in scope and be pinned for the lifetime of the chart

5. UseJaggedDataAtLocation (Zero-Copy Jagged Reference)

Same zero-copy concept as UseDataAtLocation, but for JaggedData mode. Each subset points to its own application array.

// C# .NET - Zero-copy jagged via UseJaggedDataAtLocation
// Arrays must persist — use static, class-level, or MainWindow scope
static float[][] MyXData = new float[4][];
static float[][] MyYData = new float[4][];

for (int s = 0; s <= 3; s++)
{
    MyXData[s] = new float[12];
    MyYData[s] = new float[12];
    for (int p = 0; p <= 11; p++)
    {
        MyXData[s][p] = (float)(p + 1);
        MyYData[s][p] = (float)(Rand_Num.NextDouble() * 100);
    }
}

Pesgo1.PeData.JaggedData = true;
Pesgo1.PeData.Subsets = 4;
Pesgo1.PeData.Points = 1;
for (int s = 0; s <= 3; s++)
{
    Pesgo1.PeData.X.UseJaggedDataAtLocation(MyXData[s], s);
    Pesgo1.PeData.Y.UseJaggedDataAtLocation(MyYData[s], s);
}
Pesgo1.PeFunction.ReinitializeResetImage();

Performance: Zero copy overhead - chart uses your memory directly
Best for: Large jagged datasets, multiple charts sharing same subset arrays
Requirement: Arrays must remain in scope and be pinned for the lifetime of the chart

Data Passing Method Comparison

Method.NET InterfaceC++ DLLSpeedBest Use Case
IndexerPeData.Y[s,p] = valPEvsetcellExGood<100K points, prototyping
Block CopyFastCopyFrom()PEvsetFastest100K-500K points, production
Partial CopyFastCopyFromJagged()PEvsetExFastJagged data, partial updates
Zero-CopyUseDataAtLocation()PEP_faYDATAPTRNo Copy>500K points, shared data
Zero-Copy JaggedUseJaggedDataAtLocation()PEP_faYDATAPTRNo Copy>500K jagged, shared subsets

Understanding .NET Wrapper Transparency

The .NET interfaces (Gigasoft.ProEssentials.dll) are thin wrappers around the native PEGRP64H.DLL (64-bit) or PEGRP32H.DLL (32-bit). Understanding this helps you optimize:

.NET MethodWraps DLL FunctionInternal Behavior
FastCopyFrom()PEvsetWmemcpy entire array
FastCopyFromJagged()PEvsetExmemcpy partial range
PeData.Y[s,p] = valPEvsetcellExSingle value assignment
UseDataAtLocation()PEP_faYDATAPTRSets pointer, no data copy
UseJaggedDataAtLocation()PEP_faYDATAPTRSets per-subset pointer, no copy

Data Properties by Chart Object

Different chart objects use different combinations of X, Y, Z, and W data:

Chart ObjectDescriptionData Properties Used
PegoGraph Object (bar, line, area)Y only (X is categorical via PointLabels)
PesgoScientific Graph (XY scatter, line)X, Y (numeric X axis)
Pe3do3D Scientific Graph (surfaces)X, Y, Z (optionally W for 4D)
PepsoPolar/Smith ChartX (angle/real), Y (radius/imaginary)
PepcoPie ChartY only (slice values)

Related Demo Examples

Explore these examples in the PeDemo application for working implementations:

  • Example 018 - Graph showing use of FastCopyFrom / PEvset
  • Example 142 - JaggedData simple - 4 subsets with varying points (spoon fed)
  • Example 143 - JaggedData with FastCopyFromJagged C# arrays (block passed)
  • Example 144 - JaggedData with UseJaggedDataAtLocation (zero-copy reference)
  • Example 145 - 2D Real-Time with ComputeShader and CircularBuffers
  • Example 146 - 2D Real-Time using UseDataAtLocation with CircularBuffers
  • GigaPrime3D - Data reuse between 3 charts with ComputeShader GPU rendering
 Demo Location: C:\ProEssentials10\Demo (default install)

Best Practices Summary

Quick Reference Guidelines

1. For Non-Jagged mode, set Subsets and Points before passing data

2. For <100K points, simple indexers are fine

3. For <500K points, use FastCopyFrom() or PEvset - simple and fast

4. For >500K points or real-time, consider UseDataAtLocation() for zero-copy efficiency

5. Keep your data in application arrays - maintain clear separation from chart

6. Use JaggedData only when subsets genuinely have different point counts

7. Call ReinitializeResetImage() after setting/changing data

Questions About Data Handling?

Our engineers are happy to help you determine the best data passing strategy for your specific use case. Describe your data structure and performance requirements.

Contact Support

Our Mission

Your success is our #1 goal by providing the easiest and most professional benefit to your organization and end-users.

We are Engineers

ProEssentials was born from professional Electrical Engineers needing their own charting components. Join our large list of top engineering companies using ProEssentials.

Thank You

Thank you for being a ProEssentials customer, and thank you for researching the ProEssentials charting engine.