I am trying to create a combined graph using HighCharts in a swift iOS project. The function for creating the graph is as follows.
private func createBUGraph()
{
let chartView = HIChartView(frame: self.chartHolderViewOutlet.bounds)
let options = HIOptions()
let title = HITitle()
title.text = "UTS"
options.title = title
let subtitle = HISubtitle()
subtitle.text = "Sales & Margin"
options.subtitle = subtitle
let xAxis = HIXAxis()
xAxis.categories = ["A", "B", "C", "D"]//
options.xAxis = [xAxis]
let yAxis = HIYAxis()
//yAxis.min = 0
yAxis.title = HITitle()
yAxis.title.text = "Sales"
yAxis.lineWidth = 1
let y2Axis = HIYAxis()
y2Axis.title = HITitle()
y2Axis.title.text = "Margin"
y2Axis.lineWidth = 1
y2Axis.tickPositions = [5,10,15,20]
y2Axis.opposite = true
options.yAxis = [yAxis,y2Axis]
let Sales = HIColumn()
Sales.name = "Sales"
Sales.data = [3, 2, 1, 3]
let SalesForecast = HIColumn()
SalesForecast.name = "Sales Forecast"
SalesForecast.data = 2, 3, 5, 7]
let Margin = HISeries()
Margin.name = "Margin"
Margin.data = [2.5, 1.2, 8.5, 5.5]
Margin.marker = HIMarker()
Margin.marker.lineWidth = 2
Margin.marker.symbol = "circle"
let MarginForeast = HISeries()
MarginForeast.name = "Margin Foreast"
MarginForeast.data = [3, 2.67, 3, 6.33] //
MarginForeast.marker = HIMarker()
MarginForeast.marker.lineWidth = 2
MarginForeast.marker.symbol = "circle"
options.series = [Sales, SalesForecast, Margin, MarginForeast]
chartView.options = options
self.chartHolderViewOutlet.addSubview(chartView)
}
The graph is drawing but I am stuck at the following issues
How to set automatic tick intervals in y2Axis according to the data[Opposite axis]?
How to set the series data to the y2Axis?
I tried to look for solution in highcharts documentation but I could not find any which will give me a solution.
Remove y2Axis.tickPositions = [5,10,15,20]
Set series.yAxis = 1 (API)
How to set automatic tick intervals in y2Axis according to the
data[Opposite axis]?
Remove tickPositions and use HIYAxis.linkedTo property.
How to set the series data to the y2Axis?
Use HISeries.yAxis property
API: https://api.highcharts.com/ios/highcharts/
Related
I am generating a graph using Highcharts framework in one of the iOS projects using Swift language.
The function for generating graph is as follows.
private func createBUGraph()
{
let chartView = HIChartView(frame: self.chartHolderViewOutlet.bounds)
let options = HIOptions()
let title = HITitle()
title.text = "UTS"
options.title = title
let subtitle = HISubtitle()
subtitle.text = "Sales & Margin"
options.subtitle = subtitle
let xAxis = HIXAxis()
xAxis.categories = ["A", "B", "C", "D"]//
options.xAxis = [xAxis]
let yAxis = HIYAxis()
//yAxis.min = 0
yAxis.title = HITitle()
yAxis.title.text = "Sales"
yAxis.lineWidth = 1
let y2Axis = HIYAxis()
y2Axis.title = HITitle()
y2Axis.title.text = "Margin"
y2Axis.lineWidth = 1
y2Axis.tickPositions = [5,10,15,20]
y2Axis.opposite = true
options.yAxis = [yAxis,y2Axis]
let Sales = HIColumn()
Sales.name = "Sales"
Sales.data = [3, 2, 1, 3]
let SalesForecast = HIColumn()
SalesForecast.name = "Sales Forecast"
SalesForecast.data = 2, 3, 5, 7]
let Margin = HISeries()
Margin.name = "Margin"
Margin.data = [2.5, 1.2, 8.5, 5.5]
Margin.marker = HIMarker()
Margin.marker.lineWidth = 2
Margin.marker.symbol = "circle"
let MarginForeast = HISeries()
MarginForeast.name = "Margin Foreast"
MarginForeast.data = [3, 2.67, 3, 6.33] //
MarginForeast.marker = HIMarker()
MarginForeast.marker.lineWidth = 2
MarginForeast.marker.symbol = "circle"
options.series = [Sales, SalesForecast, Margin, MarginForeast]
chartView.options = options
self.chartHolderViewOutlet.addSubview(chartView)
}
While the graph is being loaded, I need to show a loading indicator in the graph. Is there any way to show that?
Or is there any way to know whether the graph has completed loading or not?
Thanks in advance
Add any loader when ever you call Chart method and stop loader when your charts load.
These are library for loader you can use any other or by default loader by apple.
1.https://github.com/ninjaprox/NVActivityIndicatorView
2.https://github.com/relatedcode/ProgressHUD
You may try this
func createBUGraph(completion: (Bool) -> ()) {
// do stuff here
completion(true)
}
createBUGraph(completion: { (success) -> Void in
// add loader
if success {
print("true")
// hide loader
}
})
You might as well use your own loader and show it when the chart is loading.
Then you can hide it using the chartViewDidLoad function from HIChartViewDelegate
API: https://api.highcharts.com/ios/highcharts/Protocols/HIChartViewDelegate.html#//api/name/chartViewDidLoad
I'm new using Highcharts. Using it in iOS (which is pretty much the same as JS) I have this piece of code for testing:
private func initChart(){
let chart = HIChart()
let chartOptions = HIOptions()
chartOptions.chart = chart
chart.type = "line"
chartOptions.title = HITitle()
chartOptions.title.text = "Auction Details"
chartOptions.subtitle = HISubtitle()
chartOptions.subtitle.text = "P&L Curves"
let xAxis = HIXAxis()
xAxis.title = HITitle()
xAxis.title.text = "Time"
xAxis.categories = ["10-01-2018", "23-03-2018", "10-04-2018", "30-04-2018", "01-05-2018", "14-09-2018", "10-011-2018", "22-11-2018"]
chartOptions.xAxis = [xAxis]
let yAxis = HIYAxis()
yAxis.title = HITitle()
yAxis.title.text = "Money"
yAxis.min = 0.0
chartOptions.yAxis = [yAxis]
let seriesRewards = HISeries()
seriesRewards.name = "Rewards"
seriesRewards.data = [["10-01-2018", 23.4], ["23-03-2018", 34.2], ["22-11-2018",7.9]]
let seriesPrice = HISeries()
seriesPrice.name = "Price"
seriesPrice.data = [["23-03-2018",42.4], ["23-03-2018",34.2], ["10-04-2018",61.1], ["01-05-2018",87.0], ["14-09-2018",25.9], ["22-11-2018",100.1], ["01-12-2018",95.9], ["22-12-2018",81.9]]
chartOptions.series = [seriesRewards, seriesPrice]
chartView.options = chartOptions
}
This runs perfectly but it I the points for the 1st series do not match with what I said... pls take a look to the following image:
My question is, seriesRewards is defined like this:
seriesRewards.data = [["10-01-2018", 23.4], ["23-03-2018", 34.2],
["22-11-2018",7.9]]
Why the last point is not shown in the correct position in the chart?
Regards
I'd start to use Dotnet.HighCharts controls to draw charts on my page in ASP.NET MVC app.
I used Google Charts, but they don't have enough functionality.
The task is to make charts with area ranges, step line and syncronized crosshair on multiple charts. Does DotNet.HighCharts do it?
By this time i did draw only area ranges.
If not, please give me a hint, which controls can do it.
Highcharts chart = new Highcharts("chart")
.InitChart(new Chart())
.SetTitle(new Title { Text = "July temperatures" })
.SetXAxis(new XAxis { Type = AxisTypes.Datetime })
.SetYAxis(new YAxis { Title = new YAxisTitle { Text = string.Empty } })
.SetLegend(new Legend { Enabled = false })
.SetTooltip(new Tooltip
{
Crosshairs = new Crosshairs(true),
Shared = true,
ValueSuffix = "°C"
})
.SetLegend(new Legend())
.SetSeries(new[]
{
new Series
{
Name = "Temperature",
Data = ChartsData.TemperatureVariationAverages,
ZIndex = 1,
Type = ChartTypes.Line,
PlotOptionsLine = new PlotOptionsLine
{
Marker = new PlotOptionsLineMarker
{
FillColor = Color.White,
LineWidth = 2,
LineColor = Color.Black
}
}
},
new Series
{
Name = "Range",
Data = ChartsData.TemperatureVariationRanges,
Type = ChartTypes.Arearange,
ZIndex = 0,
PlotOptionsArearange = new PlotOptionsArearange
{
LineWidth = 0,
LinkedTo = ":previous",
Color = Color.Green,
FillOpacity = 0.1,
}
},
new Series
{
Name = "Range3",
Data = ChartsData.TemperatureVariationRanges1,
Type = ChartTypes.Arearange,
ZIndex = 0,
PlotOptionsArearange = new PlotOptionsArearange
{
LineWidth = 0,
LinkedTo = ":previous",
Color = Color.Red,
FillOpacity = 0.1,
}
},
new Series
{
Name = "Range2",
Data = ChartsData.TemperatureVariationRanges2,
Type = ChartTypes.Arearange,
ZIndex = 0,
PlotOptionsArearange = new PlotOptionsArearange
{
LineWidth = 0,
LinkedTo = ":previous",
Color = Color.Yellow,
FillOpacity = 0.1,
}
}
});
Hi there I'm working with Charts library and I've build some graphs, but I want to do something special with a PieChart and I can't do it yet I don't know which could be the properties to setup my pie graph like y want. Ok then I want to setup a maximum value to 100 for the graph, by setting up this, I guess that my graph will show just the number that I'm trying to show in this case es 50 and the other part of the graph should look empty. I hope yo can help me.
This is what I have now the graph has just one Double value that value is 50
This is the way that the graph should look like
func createPieGraphRedemptions() {
var chart = PieChartView()
chart = PieChartView(frame: CGRect(x: 229, y: 40, width: 165, height: 165))
let yVals: [Double] = [50]
var entries = [ ChartDataEntry]()
for (i, v) in yVals.enumerated() {
let entry = ChartDataEntry()
entry.x = Double( i)
entry.y = v
entries.append( entry)
}
let set = PieChartDataSet( values: entries, label: "Pie Chart")
set.colors = [UIColor.red]
let data = PieChartData( dataSet: set)
//data.setDrawValues(false)
chart.data = data
chart.noDataText = "No hay datos disponibles"
chart.isUserInteractionEnabled = false
chart.legend.enabled = false
chart.chartDescription?.text = ""
chart.highlighter = nil
self.view.addSubview(chart)
}
I want to initialise a list of parameters in Swift by reading text files containing eight parameter values and preserve the parameters in the same order they are read from file. Once initialised parameter values do not change. Ideally they should be accessed efficiently - and be especially clear for anyone maintaining code further down the track.
In the Playground example (below) parameter values are stored in an Array of Arrays of Strings. Raw values from the Enumeration are then used as a set of indices to address the Array. Initially I thought of using Enumeration to store parameter values as raw values to be addressed using either the parameter name or a numerical index. But from this answer I cannot see a way to assign parameter values directly to member names. In fact I'm starting to doubt whether I should be using an enumeration at all.
Can anyone offer a better way to do this ?
(This probably sounds naive as I've never used a Swift Enumeration before).
enum MapParameters: Int {
case midiChannel = 0,
sizeOfRepeatingMapPattern = 1,
firstMIDIKey = 2,
lastMIDIKey = 3,
middleKey = 4,
referenceMIDIKey = 5,
referenceFrequency = 6,
keysPerFormalOctave = 7
}
let sourceArray = ["5", "12", "0", "127", "60", "69", "440.0", "12"]
let mapIndex = MapParameters.referenceFrequency //referenceFrequency
let i = mapIndex.rawValue // 6
let parameterValue = sourceArray[i] // "440.0"
Using MapParameters enum for making what's the meaning of each index (making it more readable) of sourceArray is legal, however, that's should be valid iff the sourceArray.count is equals to 8 and its sorting is always the same.
You can use it as:
enum MapParameters: Int {
case midiChannel = 0,
sizeOfRepeatingMapPattern = 1,
firstMIDIKey = 2,
lastMIDIKey = 3,
middleKey = 4,
referenceMIDIKey = 5,
referenceFrequency = 6,
keysPerFormalOctave = 7
}
let sourceArray = ["5", "12", "0", "127", "60", "69", "440.0", "12"]
let firstMIDKeyFromSource = sourceArray[MapParameters.firstMIDIKey.rawValue] // 0
let middleKeyFromSource = sourceArray[MapParameters.middleKey.rawValue] // 60
In fact, I find the code snippet above code smell bad; There are alternatives that should be more optimized, such as: Receiving these values as a Dictionary, OR if -somehow- you have to get them as an array, you might want to map
them via a simple model, similar to:
struct MappedParameters {
// you might want to give them initial values
// or you can make them as optionals
var midiChannel = ""
var sizeOfRepeatingMapPattern = ""
var firstMIDIKey = ""
var lastMIDIKey = ""
var middleKey = ""
var referenceMIDIKey = ""
var referenceFrequency = ""
var keysPerFormalOctave = ""
init(sourceArray: [String]) {
if sourceArray.count != 8 {
fatalError("ERROR: sourceArray.count is NOT 8")
}
midiChannel = sourceArray[0]
sizeOfRepeatingMapPattern = sourceArray[1]
firstMIDIKey = sourceArray[2]
lastMIDIKey = sourceArray[3]
middleKey = sourceArray[4]
referenceMIDIKey = sourceArray[5]
referenceFrequency = sourceArray[6]
keysPerFormalOctave = sourceArray[7]
}
}
Usage:
Somewhere in your code you should implement:
let sourceArray = ["5", "12", "0", "127", "60", "69", "440.0", "12"]
let sourceMapper = MappedParameters(sourceArray: sourceArray)
and simply, use sourceMapper as:
print(sourceMapper.firstMIDIKey) // 0
print(sourceMapper.middleKey) // 60
Hope this helped.
An alternative to #Ahmad F's answer could be to use static members
struct MapParameters {
static let midiChannel = 0
static let sizeOfRepeatingMapPattern = 1
static let firstMIDIKey = 2
static let lastMIDIKey = 3
static let middleKey = 4
static let referenceMIDIKey = 5
static let referenceFrequency = 6
static let keysPerFormalOctave = 7
}
let sourceArray = ["5", "12", "0", "127", "60", "69", "440.0", "12"]
let parameterValue = sourceArray[MapParameters.referenceFrequency]