NChart3D Tutorial
Overview
This documentation provides a short tutorial that will explain the main concepts of the NChart3D framework as well as show you how to draw charts using NChart3D.
NChart3D is a versatile charting engine for macOS that lets you draw 2D and 3D interactive charts of different types according to your data.
The usage of NChart3D is very simple and requires only a few lines of code to visualize your data in a convenient and beautiful form.
Introduction
This tutorial will show you how to install NChart3D framework and build a simple project that displays some random data, how to customize the appearance of charts and how to manage the selection of data. This tutorial is partially based on the samples provided on the NChart3D macOS .dmg that can be downloaded here.
At the end of this tutorial you will be able to create a simple application that looks like this:
Installation
First, download the NChart3D macOS .dmg. It is recommended to install the framework that will allow you to add it from the "Developer Frameworks" section in Xcode. To do so, run "Install.pkg". The documentation will be installed to Xcode automatically with the framework. Alternatively you can just copy the framework to your disk and then link it through the "Add Other" option. The framework is located in the "NChart3D_OSX.framework" directory, the documentation is located in the "Documentation" directory and the set of samples is located in the "NChart3D/SwiftSamples" directory.
For each sample the Xcode-projects are already created, so you can check them out to see whether everything works properly.
This tutorial will show you how to create a project from scratch. Let’s begin!
Create a new project of the "Cocoa Application" type.
If you installed the framework properly, you should be able to link it to your application in the usual way. Click the top-level element in your project’s tree (it contains the name of your project), select the tab "General", scroll down add hit the "+" button. Then find the NChart3D_OSX.framework
that should be in the "Developer Frameworks" section.
Double click on it, and it will be linked to your project.
Add the
libc++.tbd
library and the framework ImageIO
to your project in the same way (it can by found in the "macOS xxx" section).After that add the value
$(DEVELOPER_FRAMEWORKS_DIR)
to the set of values of the option "Framework search paths"
in the project settings.Then, select the tab "Build Settings" and find property "Objective-C Bridging Header". Double click to it and drag and drop header named "NChart3D.h" from NChart3D_OSX.framework to this property. Press Enter button to confirm.
Make a test-run to check whether the project is able to build and run.
Now your project is set up and you can start using the NChart3D framework!
Anatomy of Charts
Before we start, let’s explain a little bit of terminology.
- Background — the color or gradient that fills the background.
- Caption — the text label (that can have background and border) that is displayed on top of the chart.
- Legend — the scrollable widget that contains the names and marker images of all the series on the chart.
- Plot area — the area where the series are drawn.
- Axes — axes that surrounds the plot area.
- Axes ticks — ticks that divide axes into pieces. There are major and minor ticks.
- Axes grid lines — lines on the plot area that are parallel to the axes and start in the major ticks.
- Axes labels — labels of the axes ticks.
- Axes captions — captions of the axes.
- Series — data visualizers.
- Series’ points — individual values in the series.
- Tooltip — a label on the chart displaying information about the chart point.
Drawing a Simple Chart
Let’s draw a simple chart. First, create a new NSObject’s subclass and call it, for example, MainController. Open your .XIB file (by default named MainMenu.xib) and add instance of Object from Library Palette. Set its class as MainController
.
The main class of NChart3D framework is called NChart and its instance is accessible from the NChartView. NChartView is the subclass of NSView that represents everything needed to display the chart in your views hierarchy. You can create an NChartView instance, place it anywhere you want and then communicate with the chart through the corresponding property of that instance.
After that, add the internal IBOutlet field
m_view
of the NChartView!
type to the MainController
likeclass MainController: NSObject {
@IBOutlet var m_view: NChartView!
}
@end
Override the awakeFromNib
method of MainController
like this:override func awakeFromNib() {
// Add your code there.
}
After that open your .XIB file, add Custom View as subview to your window, and set class of this view as NChartView
. After all, connect outlet m_view
to this view.Now you can customize the chart through the
m_view.chart
property.If you have a license key, set it to the chart like this:
m_view.chart.licenseKey = "Your license key"
You can put this code to awakeFromNib
method of MainController
.You may switch on anti-aliasing (that is off by default). It will not hurt performance, because the anti-aliasing algorithm is adaptive, so it is recommended to switch it on to get better visual quality of the image. Add the following line of code:
m_view.chart.shouldAntialias = true
By default, it automatically switches off to the time-critical periods like user interactions or animation playing. If you do not want this, you may use non-adaptive mode:m_view.chart.adaptiveAntialiasing = false
Antialiasing will always be switched on, but in this case you may experience lack of performance by displaying complex charts.Now you should create a series that will be displayed. First, create only one column series and assign some brush that will fill this series with color. For example, let this series be green:
let series = NChartColumnSeries()
series.brush = NChartSolidColorBrush(color: NSColor(red: 0.0, green: 0.7, blue: 0.4, alpha: 1.0))
Now you should assign a data source to that series. If you have worked with NSTableView the idea of a data source should be familiar to you. NChart3D framework uses the same concept of a data source for supplying data and delegates for reacting to user interactions.There is a protocol called NChartSeriesDataSource that you should implement to build a data source. For example, you can make a data source from
MainController
simply by adding the reference to the protocol in the MainController.swift
file as follows:class MainController: NSObject, NChartSeriesDataSource
And then add two methods that will supply data and names for the series:func seriesDataSourcePoints(for series: NChartSeries!) -> [Any]! {
var result = [NChartPoint]()
for i in 0...10 {
result.append(NChartPoint(state: NChartPointState(alignedToXWithX: i, y: Double(arc4random() % 30 + 1)),
for: series))
}
return result
}
func seriesDataSourceName(for series: NChartSeries!) -> String! {
return "My series"
}
As you can see, the first method generates an array of points with some random data. Each point can contain an array of states representing the changes of data in time. However in this tutorial we will create only one state for each point, which will be automatically the current one. Each state holds the actual data. For 2D columns the data are represented by X and Y values. We want the columns to be aligned to the X axis to make them look like "paling", so we use integer X values. The height of columns is "free", so normally double values are used, but in our case also integers are used because of the rand()
function. Feel free to experiment with different values and see what happens.The second method generates names for series to allow NChart3D to build the legend.
Now, when the data source is ready, assign it to the series you have created and finally add series to the chart:
series.dataSource = self
m_view.chart.addSeries(series)
That’s almost all we need to visualize the data. The only thing we’ve missed is to update data in the chart:m_view.chart.updateData()
This will force the NChart3D framework to process the data and build the visual appearance of the series. You should call this method any time the data was changed.
Now you can build and run your application and see what happens. You should get the following result:One more thing: NChart3D uses hardware accelerated OpenGL-based graphics to render charts, therefore it forces descrete video card (if any) by default. If you do not want this, you should add property
NSSupportsAutomaticGraphicsSwitching
with the value YES
to the Info.plist
of your app. The discrete video card consumes more energy, but ensures high rendering performance.
Customizing Appearance
As you can see, the values on the axes are calculated automatically. Let’s customize them and display some labels on the X axis! The axes as well as the series can have their own data sources. These data sources can supply custom minimums / maximums or custom strings for labels of the ticks.
Add a reference to the protocol NChartValueAxisDataSource to the MainController
:
class MainController: NSObject, NChartSeriesDataSource, NChartValueAxisDataSource
Next implement a single method that will supply the strings used for ticks' labels:func valueAxisDataSourceTicks(for axis: NChartValueAxis!) -> [Any]! {
if (axis.kind == NChartValueAxisKind.X) {
return ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven"]
}
return nil
}
We have 11 points in the series, so we should supply 11 strings.Let's also add captions to the axes. Implement the following method:
func valueAxisDataSourceName(for axis: NChartValueAxis!) -> String! {
switch (axis.kind) {
case .X:
return "X Axis"
case .Y:
return "Y Axis"
default:
return nil
}
}
This will supply names for the X and Y axes.Of course, you should set the data source to the axes you want to customize. You can do this by adding the following line before your
updateData
call:m_view.chart.cartesianSystem.xAxis.dataSource = self
m_view.chart.cartesianSystem.yAxis.dataSource = self
You can also play with the colors of chart. For example, let’s change the background to the gray-to-white gradient. For this, you can create a gradient brush and assign it to the chart’s background
property:m_view.chart.background = NChartLinearGradientBrush(from: NSColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1.0), to: NSColor.white)
You may use the multicolor gradients as well. See the documentation for NChartLinearGradientBrush for details.You can also add a border for your series, like this:
series.borderThickness = 2.0
series.borderBrush = NChartSolidColorBrush(color: NSColor.black)
Now add the caption to the chart by adding another lines to the awakeFromNib
method:m_view.chart.caption.margin = NChartMarginMake(0.0, 0.0, 0.0, 20.0)
m_view.chart.caption.text = "NChart3D"
You will get the following result:Adding More Charts
Now let’s add more series to the chart.
Just create another series of different types, for example one area and one line. To do this, add the following code after the creation of the first series:
let series2 = NChartAreaSeries()
series2.brush = NChartSolidColorBrush(color: NSColor.orange)
series2.brush.opacity = 0.7
series2.dataSource = self
m_view.chart.addSeries(series2)
let series3 = NChartLineSeries()
series3.brush = NChartSolidColorBrush(color: NSColor.red)
series3.lineThickness = 3.0
series3.dataSource = self
m_view.chart.addSeries(series3)
You should get the following result:As you can see, three series of different types appear on the chart. Wait, what? The names in the legend are all the same! Let’s fix it. First, add the tag for each series like this:
series.tag = 1
series2.tag = 2
series3.tag = 3
And then change the seriesDataSourceNameForSeries:
method to the following:func seriesDataSourceName(for series: NChartSeries!) -> String! {
return "My series \(series.tag)"
}
This will add the numbers to the series’ names that appear in the legend.
Adding Tooltips
It’s time to add tooltips that will appear and disappear by tapping chart points and display some information, for example, the name of a series and the current Y value.
To handle which chart points are selected when tapped, NChartDelegate is used. Add the reference to this protocol to MainController
:
class MainController: NSObject, NChartSeriesDataSource, NChartValueAxisDataSource, NChartDelegate
Then implement four required methods of this protocol (but we will use only one of them):func chartDelegatePointOfChart(chart: NChart!, selected point: NChartPoint!) {
m_prevSelectedPoint?.tooltip.setVisible(false, animated: 0.25)
if (point != nil) {
if (point.tooltip != nil) {
if (point == m_prevSelectedPoint) {
m_prevSelectedPoint = nil
} else {
m_prevSelectedPoint = point
updateTooltipText(point)
point.tooltip.setVisible(true, animated: 0.25)
}
} else {
m_prevSelectedPoint = point
point.tooltip = createTooltip()
updateTooltipText(point)
point.tooltip.setVisible(true, animated: 0.25)
}
} else {
m_prevSelectedPoint = nil
}
}
The logic here is pretty straightforward. We hide old tooltip (if any) with animation and then show the new one or do nothing if the selected point is the one we selected before (so second tap to the same point hides the tooltip). To make this work, we should store the previously selected point somewhere. Let’s use internal optional variable called
m_prevSelectedPoint
of type NChartPoint like this:
var m_prevSelectedPoint: NChartPoint?
Also we will need two additional methods to create and update a tooltip. You may use some initial settings for the tooltip like this:
func createTooltip() -> NChartTooltip {
let result = NChartTooltip()
result.background = NChartSolidColorBrush(color: NSColor.white)
result.background.opacity = 0.9
result.padding = NChartMarginMake(10.0, 10.0, 10.0, 10.0)
result.borderColor = NSColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1.0)
result.borderThickness = 1.0
result.font = NSFont.systemFont(ofSize: 16.0)
result.visible = false
return result
}
And then you should update the text in the tooltip:func updateTooltipText(point: NChartPoint) {
point.tooltip.text = "\(point.series.name!) : \(point.currentState.doubleY)"
}
As you can see, you can display any information in the tooltip you want. Finally set the delegate for chart by adding the following line to the
awakeFromNib
method:m_view.chart.delegate = self;
And that’s it! You should get something like this:What's next?
You can find more information about using the NChart3D framework in samples on the macOS .dmg. If you have any questions, feel free to contact us.