Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Y Axis value repeat in BarChart and Zero Y Axis position is not there in Positive and Negative BarChart. #5066

Open
lokesh-vyas opened this issue Jun 2, 2023 · 1 comment

Comments

@lokesh-vyas
Copy link

lokesh-vyas commented Jun 2, 2023

We are facing mainly two issue

  1. Y Axis value is repeat for large number in Bar Chart despite we are using granularityEnable and setting value as well. We have use below OIAnalysisLargeValueFormatter but it seems it is working but granularity is not taking correct value.
Screenshot 2023-06-02 at 12 01 52 PM

`final class OIAnalysisLargeValueFormatter: AxisValueFormatter {

var suffix = ["", "k", "L", "Cr"]

public init() { }

fileprivate func format(value: Double) -> String {
    var sig = value
    var length = 3
    var fraction = 0
    
    let numberFormatter = NumberFormatter()
    numberFormatter.usesGroupingSeparator = true
    numberFormatter.negativePrefix = "-"
    
    if abs(sig) >= 10000000 {
        sig = (Double(sig) / 100000000)
        sig *= 10
        length -= 0
        numberFormatter.maximumFractionDigits = 1
    } else if abs(sig) >= 100000 {
        sig = (Double(sig) / 1000000).rounded()
        sig *= 10
        length -= 1
        numberFormatter.maximumFractionDigits = 0
    } else if abs(sig) >= 10000 {
        sig = (Double(sig) / 10000).rounded() //' K'
        length -= 2
    } else {
        length -= 3  // ""
    }
    
    let number = NSNumber(value: sig)
    
    numberFormatter.maximumFractionDigits = fraction
    numberFormatter.positiveSuffix = suffix[length]
    numberFormatter.negativeSuffix = suffix[length]
    
    guard let string = numberFormatter.string(from: number) else {
        return NumberFormatter.localizedString(from: number, number: .decimal)
    }
    
    return string
}

func stringForValue(
    _ value: Double, axis: AxisBase?) -> String {
        return format(value: value)
    }

func stringForValue(
    _ value: Double,
    entry: ChartDataEntry,
    dataSetIndex: Int,
    viewPortHandler: ViewPortHandler?) -> String {
        return format(value: value)
    }

}`

2. In positive negative chart it is not showing Zero position as Axis in between.

Screenshot 2023-06-02 at 12 02 42 PM

'Data Building :- >
OiAnalysisChartDataBuilder
func processOIChartDataSet(strikes: [Strike], spotPrice: Double) -> ViewController.Content {
var dataEntries = [BarChartDataEntry]
var callEntries = BarChartDataEntry
var putEntries = BarChartDataEntry
var xAxisValues = String

strikes.enumerated().forEach {
  let data = OiAnalysisToolTipModel(chartType: .oi,
                                    strikePrice: $0.element.strikePrice,
                                    callOi: $0.element.calloi,
                                    putOi: $0.element.putoi,
                                    firstColorView: Constants.colorSets[0] ?? .green,
                                    secondColorView: Constants.colorSets[1] ?? .red)
  xAxisValues.append(String(Int($0.element.strikePrice)))
  callEntries.append(BarChartDataEntry(x: $0.element.strikePrice, y: $0.element.calloi, data: data))
  putEntries.append(BarChartDataEntry(x: $0.element.strikePrice, y: $0.element.putoi, data: data))
}

callEntries.insert(BarChartDataEntry(x: 0, y: 0), at: 0)
putEntries.insert(BarChartDataEntry(x: 0, y: 0), at: 0)
dataEntries.append(callEntries)
dataEntries.append(putEntries)
return processChartResponse(chartType: .oi,
                            barData: dataEntries,
                            title: OiFilterTabs.OiFilterSecondaryFilter.oi.title,
                            spotPrice: spotPrice,
                            xAxisBarValues: xAxisValues)

}'

CHART CODE:

'extension ViewController {

struct Content {
    
    let chartType: OiFilterTabs.OiFilterSecondaryFilter
    let chartDataSets: [OiFNOChartDataSet]
    let spotPrice: Double
    let xAxisBarValues: [String]
    weak var chartViewDelegate: ChartViewDelegate?
    
    init(chartType: OiFilterTabs.OiFilterSecondaryFilter,
         chartDataSets: [OiFNOChartDataSet],
         spotPrice: Double = 0.0,
         xAxisBarValues: [String] = [],
         chartViewDelegate: ChartViewDelegate? = nil) {
        self.chartType = chartType
        self.chartDataSets = chartDataSets
        self.spotPrice = spotPrice
        self.xAxisBarValues = xAxisBarValues
        self.chartViewDelegate = chartViewDelegate
    }
    
}

struct OiFNOChartDataSet {
    
    let entries: [ChartDataEntry]
    let barChartEntries: [BarChartDataEntry]
    let color: UIColor
    let title: String
    
}

func setUpChart() {
    let legend = barChartView.legend
    legend.enabled = false
    
    barChartView.xAxis.drawGridLinesEnabled = false
    barChartView.xAxis.labelPosition = .bottom
    barChartView.xAxis.labelTextColor = .gray
    barChartView.xAxis.centerAxisLabelsEnabled = true
    barChartView.xAxis.axisLineColor = .gray
    barChartView.xAxis.granularityEnabled = true
    barChartView.xAxis.enabled = true
    
    barChartView.leftAxis.drawGridLinesEnabled = false
    barChartView.leftAxis.drawAxisLineEnabled = false
    barChartView.leftAxis.labelTextColor = .gray
    barChartView.leftAxis.drawZeroLineEnabled = true
    barChartView.leftAxis.valueFormatter = OIAnalysisLargeValueFormatter()
    barChartView.leftAxis.granularityEnabled = true
    barChartView.leftAxis.enabled = true
    
    barChartView.rightAxis.drawAxisLineEnabled = false
    barChartView.rightAxis.drawGridLinesEnabled = true
    barChartView.rightAxis.drawLabelsEnabled = false
    barChartView.rightAxis.gridColor = .gray
    
    barChartView.pinchZoomEnabled = false
    barChartView.dragXEnabled = true
    barChartView.setScaleEnabled(false)
    barChartView.scaleXEnabled = false
    barChartView.scaleYEnabled = false
    barChartView.extraRightOffset = Constants.defaultMargin
    barChartView.extraLeftOffset = Constants.defaultMargin
}

func configure(_ content: Content) {
    
    barChartView.delegate = content.chartViewDelegate
    let dataSets = content.chartDataSets.enumerated().map {
        getBarChartDataSet($0.element.barChartEntries, color: $0.element.color, label: $0.element.title, highlightEnabled: content.chartViewDelegate != nil)
    }
    
    let chartData = BarChartData(dataSets: dataSets)
    
    barChartView.leftAxis.setLabelCount(Constants.leftAxisOICount, force: true)
    barChartView.rightAxis.setLabelCount(Constants.leftAxisOICount, force: true)
    
    barChartView.xAxis.valueFormatter = OiBarChartValueXAxisFormatter(values: content.xAxisBarValues)
    
    chartData.barWidth = Constants.barWidth
    
    barChartView.xAxis.granularity = barChartView.xAxis.axisMaximum / Double(content.xAxisBarValues.count)
    
    barChartView.leftAxis.spaceBottom = 0.0
    barChartView.xAxis.axisMinimum = 0.0
    barChartView.xAxis.axisMaximum = 0.0 + chartData.groupWidth(groupSpace: Constants.groupSpace, barSpace: Constants.barSpace) * Double(content.xAxisBarValues.count)
    
    chartData.groupBars(fromX: 0.0, groupSpace: Constants.groupSpace, barSpace: Constants.barSpace)
    
    barChartView.data = chartData
    
    self.getBarGranuraltiy(axisCount: Constants.leftAxisOICount, chartMax: barChartView.chartYMax)
    barChartView.notifyDataSetChanged()
    barChartView.setVisibleXRangeMaximum(Constants.xRangeMaximum)
    barChartView.animate(yAxisDuration: Constants.yAxisDuration, easingOption: .linear)
    
    addSpotPriceLine(spotPrice: content.spotPrice, values: content.xAxisBarValues)
    
    barChartView.xAxisRenderer = LimitLineLabelRenderer(
        viewPortHandler: barChartView.viewPortHandler,
        axis: barChartView.xAxis,
        transformer: barChartView.getTransformer(forAxis: .left)
    )
    
}

func getBarGranuraltiy(axisCount: Int, chartMax: Double) -> Double {
    let count = String(Int(chartMax)).count - 1
    let c = NSDecimalNumber(decimal: pow(10, count)).doubleValue
    let d = (chartMax / c).rounded() * c
    
    let granuraltiy = (d / Double(axisCount)).rounded(.toNearestOrAwayFromZero)
    
    let granuraltiyCount = String(Int(granuraltiy)).count - 1
    let granuraltiyNumber = NSDecimalNumber(decimal: pow(10, granuraltiyCount)).doubleValue
    let finalValue = (granuraltiy / granuraltiyNumber).rounded() * granuraltiyNumber
    debugPrint(finalValue)
    return finalValue < (20 * 100000) ? (20 * 100000) : finalValue
}

}

// MARK: - Constant Helper

private typealias ConstantHelper = ViewController
private extension ConstantHelper {

enum Constants {

static let defaultMargin: CGFloat = 16.0
  
static let dashLineWidth: CGFloat = 1.0
static let xOffsetLimitLine: CGFloat = 50.0
static let yOffsetLimitLine = 4.0

// Line Chart
static let chartViewHeight: CGFloat = 315.0
static let lineWidth: CGFloat = 2.0
static let rightLeftAxisCount: Int = 8
static let chartMaxRange: Int = 120

// Bar Chart
static let granularity = 50.0
static let leftAxisOICount: Int = 6
static let groupSpace = 0.4
static let barWidth = 0.2
static let barSpace = 0.03
static let xRangeMaximum = 5.0
static let yAxisDuration = 0.5
static let barDashPhase = 5.0
static let barDashLineWidth = 1.0

static var xAxisValueForPCRAndMAX: [String] = {
  ["9:15", "10:15", "11:15", "12:15", "01:15", "02:15", "03:15"]
}()

}

}

// MARK: - OiLineChartValuexAxisFormatter

private class OiLineChartValuexAxisFormatter: AxisValueFormatter {

func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let index = Int(value) < titleValues.count ? Int(value) : Int(value / 20)
return titleValues[index]
}

var titleValues = String

init(values: [String]) {
self.titleValues = values
}

}

// MARK: - OiBarChartValueXAxisFormatter

private class OiBarChartValueXAxisFormatter: AxisValueFormatter {

var titleValues = String

init(values: [String]) {
self.titleValues = values
}

func stringForValue(_ value: Double, axis: AxisBase?) -> String {

let count = self.titleValues.count
guard let axis = axis, !self.titleValues.isEmpty else { return "" }

let factor = axis.axisMaximum / Double(count)
let index = Int((value / factor).rounded())

if index >= 0 && index < count {
  return self.titleValues[index]
}
return ""

}

}

// MARK: - ChartDataHelper Helper

private typealias ChartDataHelper = ViewController
private extension ChartDataHelper {

func getBarChartDataSet(_ chartDataEntries: [BarChartDataEntry],
color: UIColor,
label: String,
highlightEnabled: Bool) -> BarChartDataSet {
let chartDataSet = BarChartDataSet(entries: chartDataEntries, label: label)
chartDataSet.colors = [color]
chartDataSet.drawIconsEnabled = false
chartDataSet.drawValuesEnabled = false
chartDataSet.highlightEnabled = highlightEnabled
chartDataSet.highlightColor = .clear
chartDataSet.highlightLineWidth = Constants.dashLineWidth
chartDataSet.highlightLineDashPhase = Constants.barDashPhase
chartDataSet.highlightLineDashLengths = [Constants.barDashPhase, Constants.barDashPhase]
return chartDataSet
}

func addSpotPriceLine(spotPrice: Double, values: [String]) {
guard let value = values.first?.toDouble, let value2 = values[1].toDouble else { return }
let limitPoint = ((spotPrice - value) / (value2 - value)) - 1.0
let limitLine = ChartLimitLine(limit: limitPoint, label: "Spot price: " + String(spotPrice))
limitLine.lineWidth = Constants.barDashLineWidth
limitLine.lineColor = UIColor.gray
limitLine.valueTextColor = UIColor.gray
limitLine.lineDashLengths = [Constants.barDashPhase, Constants.barDashPhase]
limitLine.labelPosition = .rightTop
limitLine.xOffset = -Constants.xOffsetLimitLine
limitLine.yOffset = -Constants.yOffsetLimitLine

barChartView.xAxis.removeAllLimitLines()
barChartView.xAxis.addLimitLine(limitLine)
barChartView.xAxis.gridLineDashLengths = [5, 5]
barChartView.xAxis.drawLimitLinesBehindDataEnabled = true
barChartView.centerViewTo(xValue: limitPoint, yValue: 0, axis: .left)

}

}'

Charts Environment

##Chart Version : 4.1.0
##Xcode : 14.2
##5.6
##iPhone

Demo Project

https://github.com/lokesh-vyas/DemoChartBar

ℹ Please link to or upload a project we can download that reproduces the issue.

  1. Open App
  2. In OI tab yAxis value is repeating.
  3. in Change OI and PCR Zero yAxis is not showing while added 0 data in ChartDataBuilder.
@lokesh-vyas lokesh-vyas changed the title Y Axis value repeat in BarChart and Zero Y Axis position is not there in BarChart. Y Axis value repeat in BarChart and Zero Y Axis position is not there in Positive and Negative BarChart. Jun 2, 2023
@lokesh-vyas
Copy link
Author

lokesh-vyas commented Jun 7, 2023

Any update on this, how we can resolve both issue.
@danielgindi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant