Creating a Campbell Diagram Chart with LightningChart .NET
Tutorial
A Campbell diagram is a graph used in modeling turbulence and rotational dynamics. Learn how to create a Campbell Diagram in C#.
Introduction
In this article’s exercise, we will create a Campbell chart in .NET, using the Lightning Chart .NET library. As always, you can download the complete project attached to this article but remember to have a recent version of .NET and Visual Studio.
To create the project from scratch, we will use the Lightning Chart interactive examples tool, so I recommend that you install it so that you can generate this project from scratch if you wish. You will also be able to access the catalog of charts that LC .NET offers.
This application has its free trial version, so you will have no problems using it. That said, let’s get started!
Campbell Diagram
A Campbell diagram (named after Wilfred Campbell) is a type of graph used in modeling turbulence and rotational dynamics. This diagram shows how the rate at which turbulence kinetic energy is dissipated and the scale of turbulence within a flow are related.
It is especially useful for studying boundary layers or turbulent shear flows, helping to understand the turbulent characteristics of such a flow. This graph also represents the response spectrum of a system as a function of its oscillation regime. These diagrams are commonly used to understand the dynamic behavior of rotating machines.
- It is used to analyze the dynamic stability of mechanical systems, especially rotating ones (such as turbines, motors, generators, etc.), where the frequencies of the excitation forces can vary with the rotation speed.
- Engineers use the Campbell diagram to identify potential resonance problems that may occur at certain speeds and adjust the design to avoid coincidence between the system’s natural frequencies and the excitation frequencies.
A traditional Campbell diagram uses a rotor motion equation to express the external force due to the rotation frequency as a periodic function. This function is represented on a graph, allowing the vibration characteristics of the system to be analyzed.
A transient Campbell diagram, on the other hand, is based on a test or simulation of a complex rotor system, for which a mode equation cannot be formulated.
To create a Campbell diagram, one must follow the increase in RPM over time and record the system response at each RPM state. This data is then divided and fed into a Fast Fourier Transform (FFT) algorithm to display the frequency response in a 3D graph.
If a constant increase in RPM can be implemented in the rotor system, the frequency response characteristics of the system can be obtained and a graphical representation like a mathematical Campbell diagram can be generated.
Parameters:
- Excitation frequency (on the x-axis): This represents the variation in the frequency of the external forces that affect the system.
- Natural frequency (on the y-axis): Corresponds to the frequencies at which the vibration modes of the system tend to oscillate.
Resonance curves: Indicated by the intersections of the excitation frequencies and the natural frequencies, indicating critical zones where resonances can occur.
Project Overview
Feel free to download the ZIP file to follow this Campbell Diagram project.
Download the project to follow the tutorial
Local Setup
- OS: 32-bit or 64-bit Windows Vista or later, Windows Server 2008 R2 or later.
- DirectX: 9.0c (Shader model 3 and higher) or 11.0 compatible graphics adapter.
- Visual Studio: 2022 for development, not required for deployment.
- Platform .NET Framework: installed version 8.0 or newer.
Now go to the next URL and download LightningChart .NET. You’ll then be redirected to a sign-in form where you’ll have to complete a simple sign-up process to get access to your LightningChart account.
After signing in to your account, you can download the SDK “free trial” version that allows you to use important features for this tutorial. When you download the SDK, you’ll have a .exe file like this:
The installation will be a typical Windows process, so please continue with it until it is finished. After the installation, you will see the following programs:
License Manager
In this application, you will see the purchase options. All the projects that you will create with this trial SDK will be available for future developments with all features enabled.
Code Behind
This code creates a chart, optimizes performance, sets margins, and clears any previous data series to prepare the chart for new data.
Creating a Chart:
The code starts by creating a new chart object called _chart using the LightningChart class. It also gives the chart the name, “Campbell diagram chart”. This is essentially initializing a blank chart to work with.
Begin Chart Update:
The BeginUpdate() method is called to disable rendering (displaying the chart) temporarily. This is done to prevent the chart from refreshing every time a property is changed, which makes the updates more efficient. It allows multiple changes to be made to the chart before it’s rendered again.
Memory and Performance Optimization:
The properties DropOldSeriesData and DropOldEventMarkers are set to false. This means that the chart won’t discard old series data or event markers, which helps preserve memory and improve performance.
Setting Margins:
The Margins property of the chart’s XY view is adjusted to set the bottom margin to 100. This changes the space at the bottom of the chart.
Clear Point Line Series:
Finally, the PointLineSeries.Clear() method is called to remove all existing point line series (visual data representations like lines connecting points) from the chart. This clears out any previous data, preparing the chart for new data.
private void CreateChart()
{
// Create a new chart.
_chart = new LightningChart
{
ChartName = "Campbell diagram chart"
};
//Disable rendering, strongly recommended before updating chart properties
_chart.BeginUpdate();
//Reduce memory usage and increase performance
_chart.ViewXY.DropOldSeriesData = false;
_chart.ViewXY.DropOldEventMarkers = false;
//Setup margins
Thickness margins = _chart.ViewXY.Margins;
margins.Bottom = 100;
_chart.ViewXY.Margins = margins;
//Remove all point line series
_chart.ViewXY.PointLineSeries.Clear();
The following code configures various elements of a chart, specifically the legend box and axes (X and Y):
- Make the Legend Box Visible: This makes the first legend box visible on the chart.
ViewXY.LegendBoxes[0].Visible = true;
- Position the Legend Box: The legend box is positioned at the top center of the chart.
ViewXY.LegendBoxes[0].Position = LegendBoxPositionXY.TopCenter;
- Offset the Legend Box: This sets an offset of 0 on the X-axis (no shift) and 20 on the Y-axis (moves it down 20 units).
ViewXY.LegendBoxes[0].Offset.SetValues(0, 20);
- Layout of Legend Items: This sets the legend items to be laid out in a horizontal row.
ViewXY.LegendBoxes[0].Layout = LegendBoxLayout.HorizontalRowSpan;
- Hide Checkboxes in the Legend: This disables checkboxes next to the legend items, so users cannot toggle series visibility via checkboxes.
ViewXY.LegendBoxes[0].ShowCheckboxes = false;
X-Axis Configuration:
- Set X-Axis Range: This defines the visible range of the X-axis, from 1000 to 6500.
ViewXY.XAxes[0].SetRange(1000, 6500);
- Disable X-Axis Scrolling: This disables scrolling on the X-axis (meaning users can’t drag to zoom or move the axis).
ViewXY.XAxes[0].ScrollMode = XAxisScrollMode.None;
- Set X-Axis Label Format: This formats the X-axis labels to show whole numbers (no decimal places).
ViewXY.XAxes[0].LabelsNumberFormat = "0";
- Disable Automatic Division Spacing: This prevents automatic spacing for axis divisions, meaning you can manually control the divisions.
ViewXY.XAxes[0].AutoDivSpacing = false;
- Set Major Divisions on X-Axis: The X-axis will have major divisions every 500 units.
ViewXY.XAxes[0].MajorDiv = 500;
- Set X-Axis Value Type: This specifies that the X-axis will use numeric values.
ViewXY.XAxes[0].ValueType = AxisValueType.Number;
- Set X-Axis Title: The title of the X-axis is set to “Engine speed (rpm)”.
ViewXY.XAxes[0].Title.Text = "Engine speed (rpm)";
- Make X-Axis Title Visible and Change Color:
ViewXY.XAxes[0].Title.Visible = true;
- The title of the X-axis is made visible:
ViewXY.XAxes[0].Title.Color = Colors.White;
- The color of the X-axis title is set to white.
// Configure x-axis.
_chart.ViewXY.XAxes[0].SetRange(1000, 6500);
_chart.ViewXY.XAxes[0].ScrollMode = XAxisScrollMode.None;
_chart.ViewXY.XAxes[0].LabelsNumberFormat = "0";
_chart.ViewXY.XAxes[0].AutoDivSpacing = false;
_chart.ViewXY.XAxes[0].MajorDiv = 500;
_chart.ViewXY.XAxes[0].ValueType = AxisValueType.Number;
_chart.ViewXY.XAxes[0].Title.Text = "Engine speed (rpm)";
_chart.ViewXY.XAxes[0].Title.Visible = true;
_chart.ViewXY.XAxes[0].Title.Color = Colors.White;
Y-Axis Configuration:
- Set Y-Axis Title: The title of the Y-axis is set to “Frequency (Hz)”.
ViewXY.YAxes[0].Title.Text = "Frequency (Hz)";
- Disable Automatic Division Spacing: Like the X-axis, this disables automatic division spacing for the Y-axis.
ViewXY.YAxes[0].AutoDivSpacing = false;
- Set Major Divisions on Y-Axis: The Y-axis will have major divisions for every 100 units.
ViewXY.YAxes[0].MajorDiv = 100;
- Enable Y-Axis Snapping to Divisions: This means when users drag or zoom the Y-axis, it will snap to the nearest division mark.
ViewXY.YAxes[0].DragSnapToDiv = true;
- Set Y-Axis Range: The visible range for the Y-axis is set between 0 and 1000.
ViewXY.YAxes[0].SetRange(0, 1000);
- Change Y-Axis Title Color: The Y-axis title color is set to white.
ViewXY.YAxes[0].Title.Color = Colors.White;
- Hide Y-Axis Units: This hides the units (e.g., Hz) next to the Y-axis values.
ViewXY.YAxes[0].Units.Visible = false;
// Configure y-axis.
_chart.ViewXY.YAxes[0].Title.Text = "Frequency (Hz)";
_chart.ViewXY.YAxes[0].AutoDivSpacing = false;
_chart.ViewXY.YAxes[0].MajorDiv = 100;
_chart.ViewXY.YAxes[0].DragSnapToDiv = true;
_chart.ViewXY.YAxes[0].SetRange(0, 1000);
_chart.ViewXY.YAxes[0].Title.Color = Colors.White;
_chart.ViewXY.YAxes[0].Units.Visible = false;
Adding markers:
This code adds event markers (which are not bound to axes) to the chart to create a “legend” of sorts. These markers are used to highlight specific points on the chart, in this case, representing different dB levels (60 dB, 40 dB, and 20 dB). Each marker has a label, a shape, and a position on the chart.
- Font Setup: A font is created using
WpfFont, with the font “Segoe UI”, size 16, bold (true), and not italic (false).
- Text Shadow: A shadow effect for the text is created with no shadow style (TextShadowStyle.Off), meaning no shadow will be applied to the text.
- Label (EventMarkerTitle): A label is created for each marker (e.g., “60 dB(A)”). This label includes alignment (right and center), the font, the text color (white), a small offset, and the previously defined shadow.
- Point Shape Style: The shape and appearance of the marker are defined here:
- Color: A red color (with alpha transparency).
- Size: Width and height of 60 (for the 60 dB marker).
- Other Style Options: Various graphical options like border color, gradient style, and direction are set.
- Event Marker: A ChartEventMarker is created to combine the label and shape. It specifies the position of the marker on the chart and other properties, like whether it should be clickable or not (false).
- Add to Chart: The marker is added to the chart’s collection of event markers.
(_chart.ViewXY.ChartEventMarkers).
//Add some chart markers (not bound to axes) for making a "legend"
WpfFont font = new WpfFont("Segoe UI", 16f, true, false);
//60 db
TextShadow shadow60 = new TextShadow(null)
{
Style = TextShadowStyle.Off
};
EventMarkerTitle label60 = new EventMarkerTitle(null, "60 dB(A)", AlignmentHorizontal.Right, AlignmentVertical.Center,
font, Colors.White, 0, 5, shadow60);
PointShapeStyle pss60 = new PointShapeStyle(null, _shape, Color.FromArgb(0, 255, 0, 0), Colors.Red,
Colors.Black, Colors.Black, 60, 60,
0, 0, 1, GradientFillPoint.Edge, Direction.Up, null);
ChartEventMarker marker60 = new ChartEventMarker(_chart.ViewXY, pss60, ChartEventMarkerVerticalPosition.GraphTop, false, null,
0, label60, new PointInt(150, 140));
_chart.ViewXY.ChartEventMarkers.Add(marker60);
Code Behind – SetDataPoints()
This code will populate a chart with a series of calculated data points across multiple measurement sets. The points are related to vibration or frequency analysis, represented in a Campbell diagram format, and the chart is updated after all the points are added.
Chart Update Preparation:
The code begins by disabling the rendering of the chart to improve performance during updates with _chart.BeginUpdate().
Data Structure Setup:
- An array of
dataPointsis created to hold all the data points (of typeCampbellDataPoint) that will be added to the chart. The array is a large size to accommodate multiple sets of measurements. - A variable
pointIndexis used to track the position in the dataPoints array as new points are added.
Font Setup:
A specific font is defined for labeling or displaying text on the chart, using the WpfFont class.
Adding Data Points for Each Measurement Set:
- The code defines a series of measurement sets for different curves (1E, 2E, 3E, etc.). For each curve, a series of CampbellDataPoint objects is created with:
- A frequency value (e.g., 2600, 2700),
- A corresponding Y-value calculated by the function CalcDataPointY(),
- A specific amplitude or value associated with that frequency.
- These data points are added sequentially to the dataPoints array, with pointIndex updated each time a new data point is added.
Adding Data Points to Chart:
After each set of points for a curve is added to the dataPoints array, the AddPoint() function is called in a loop to add those points to the chart with the specified font.
Repeat for Other Curves:
The process is repeated for different curves (1E, 2E, 3E, etc.), each with its own set of frequency and amplitude data points.
Final Update:
Once all points have been added, the chart rendering is enabled again with _chart.EndUpdate() to display the updated chart.
private void SetDataPoints()
{
//Disable rendering, strongly recommended before updating chart properties
_chart.BeginUpdate();
//Array of data
CampbellDataPoint[] dataPoints = new CampbellDataPoint[12 + 14 + 7 + 17 + 3 + 17 + 3 + 4 + 3 + 3];
//Index to array
int pointIndex = 0;
//Font
WpfFont font = new WpfFont("Segoe UI", 16f, false, false);
//1E curve, 1st measurement set
int orderStartPointIndex = pointIndex;
int orderNumber = 1;
dataPoints[pointIndex++] = new CampbellDataPoint(2600, CalcDataPointY(2600, orderNumber), 40);
dataPoints[pointIndex++] = new CampbellDataPoint(2700, CalcDataPointY(2700, orderNumber), 50);
dataPoints[pointIndex++] = new CampbellDataPoint(2800, CalcDataPointY(2800, orderNumber), 60);
dataPoints[pointIndex++] = new CampbellDataPoint(2900, CalcDataPointY(2900, orderNumber), 50);
dataPoints[pointIndex++] = new CampbellDataPoint(3000, CalcDataPointY(3000, orderNumber), 45);
dataPoints[pointIndex++] = new CampbellDataPoint(3100, CalcDataPointY(3100, orderNumber), 40);
dataPoints[pointIndex++] = new CampbellDataPoint(3200, CalcDataPointY(3200, orderNumber), 35);
dataPoints[pointIndex++] = new CampbellDataPoint(3300, CalcDataPointY(3300, orderNumber), 30);
//1E curve, 2nd measurement set
dataPoints[pointIndex++] = new CampbellDataPoint(6200, CalcDataPointY(6200, orderNumber), 30);
dataPoints[pointIndex++] = new CampbellDataPoint(6300, CalcDataPointY(6300, orderNumber), 25);
dataPoints[pointIndex++] = new CampbellDataPoint(6400, CalcDataPointY(6400, orderNumber), 35);
dataPoints[pointIndex++] = new CampbellDataPoint(6500, CalcDataPointY(6500, orderNumber), 40);
for (int i = orderStartPointIndex; i < pointIndex; i++)
{
AddPoint(dataPoints[i], font);
}
Functions Used:
CampbellDataPoint(): Creates a data point with frequency, Y-value, and amplitude.
public CampbellDataPoint(double x, double y, double dba)
{
X = x;
Y = y;
dBA = dba;
}
CalcDataPointY(): A function used to calculate the Y-value for a given frequency and order number.
private double CalcDataPointY(int orderNumber, double x)
{
return (orderNumber * 100.0) / 6000.0 * x;
}
AddPoint(): Adds a data point to the chart with a specified font and style.
private void AddPoint(CampbellDataPoint dataPoint, WpfFont font)
{
float fSize = (float)(dataPoint.dBA);
EventMarkerTitle label = new EventMarkerTitle(null, "", AlignmentHorizontal.Center, AlignmentVertical.Center,
font, Colors.Black, 0, 5, new TextShadow(null));
SeriesMarkerPointShapeStyle pss = new SeriesMarkerPointShapeStyle(null, (SeriesMarkerPointShape)_shape, Color.FromArgb(0, 255, 0, 0), Colors.Red,
Colors.Black, Colors.Black, fSize, fSize,
0, 0, 1, GradientFillPoint.Edge, Direction.Up, null);
SeriesEventMarker marker = new SeriesEventMarker(_dataPointsBindSeries,
pss, SeriesEventMarkerVerticalPosition.AtYValue,
dataPoint.X, dataPoint.Y, label)
{
AllowDragging = _allowMouseMove,
Highlight = _allowMouseMove ? Highlight.Blink : Highlight.None,
HorizontalPosition = SeriesEventMarkerHorizontalPosition.AtXValue
};
_dataPointsBindSeries.SeriesEventMarkers.Add(marker);
}
Conclusion
Thank you for getting this far! This is the first time I must analyze and work with Campbell diagrams. Honestly, what I can analyze is quite interesting. I think it will be a good idea to continue working with this chart in the future, don’t you think?
At the beginning of my working life, I was lucky enough to be able to work as a maintenance mechanic. I worked with rotors, electric motors and screw compressors. Taking that into account, the Campbell chart gains much more importance, because preventive diagnoses can be made on the state of rotating equipment.
A corrective service is usually very expensive, and even more so if faults are not diagnosed in time. A Campbell diagram offers us a historical analysis of the dynamics of equipment.
LC .NET again offers us tools to create complex charts, with an intuitive implementation. This chart is at an intermediate level, so, if you have worked with LC .NET, it will not be very difficult for you to understand it.
Remember that a Campbell chart in LC .NET can be created with the help of PointLineSeries, PointShapeStyle, and EventMarkerTitle components. PointLineSeries will help us generate the lines, while the markers can be created with EventMarkerTitle and shaped as we need with PointShapeStyle.
I hope you liked this article. Remember that we have an extensive catalog of .NET, JS, and Python articles. Bye!
Continue learning with LightningChart
Best Apache ECharts Alternative in 2026: When Canvas Hits Its Ceiling
Apache ECharts is an excellent charting library that's the honest starting point, and it's worth saying clearly. Free under the Apache 2.0 license, actively maintained by one of the most active open-source communities in data visualization, with 60,000+ GitHub stars...
Best D3.js Alternatives in 2026: Less Code, More Performance, Same Power
D3.js is the most starred data visualization library in existence 109,000+ GitHub stars and for justifiable reasons. It provides the building blocks to construct any visualization imaginable: data binding, SVG path generation, scale functions, geographic projections,...
Best ApexCharts Alternatives in 2026: Scale Beyond SVG, Add Real 3D
ApexCharts earned its position through a set of genuine strengths executed consistently well: MIT license, the best default visual aesthetics among free JavaScript chart libraries, official and actively maintained React, Vue, and Angular component wrappers, clean...
