Charts: (v3.0 + Swift3.0)ChartView highlightValueWithX not working

Created on 20 Sep 2016  ·  23Comments  ·  Source: danielgindi/Charts

ChartView highlightValueWithX method seems to stop working for v3.0 + Swift3.0
Xcode 8/Master branch/Objc.

bug ★★★

Most helpful comment

Change this line: lineChartView.highlightValue(x: 3, dataSetIndex: 0)

to: lineChartView.highlightValue(Highlight(x: 3, y: 0, dataSetIndex: 0)

All 23 comments

@PhilJay highlightValue(x...) functions are failing, because the highlight renderer expects a Y value to be present. The outcome is a NaN, which causes it to render nowhere...

Both Android and iOS?

Yeah...

Hmmm... just looked through the code, this is a tricky one. For the case that we have multiple entries on the same x-position, it won't be possible to successfully highlight a certain entry without any specification of the y-position.

So maybe we should drop this method?
Another option would be to include the y-position in the method (as a parameter)?

Well the problem starts with selection from touch events - it still does not really work, if you have a scatter or bubble charts with multiple values on same x. It actually selects the first or last one on the same x - depending on the position of the touch on the X axis!

After we fix that - I guess out algorithm will know to take a Y value and after reaching the correct X it will start searching for the correct Y.
And then we'll have the option to pass a Y value, as a separate method! :-)
The original one, to highlight simply by an X is very useful and many many people depend on it, judging by the issues... So we'll get hate-mail if we remove that :-)

Is there any current work around to programmatically highlight a line chart item? Are all the highlight methods broken at the moment?

@apurva line chart should work just fine. I checked ChartsDemo with latest mater branch

Programmatically highlight still not working in line charts.

I try to highlight the last value:

[self.lineChartView highlightValueWithX:self.lineChartView.chartXMax dataSetIndex:0 callDelegate:YES];

But in delegate method - (void)chartValueSelected:entry:highlight: highlight.xPx and highlight.yPx are NaN.

I can re-confirm that highlightValueWithX is not working.

I tried creating a highlight
ChartHighlight * high = [[ChartHighlight alloc]initWithX:(double)someInt dataSetIndex:0];
and used the highlightValueWithHighlight method with it but still does not highlight. The chartValueSelected: entry: highlight: delegate method is called, that contains the correct values in the entry object but the highlight object has a NaN in the y value.

Is there any way to create a ChartHighlight * object containing the y value as well? I see various init methods for the ChartHighlight class but all others need absolute pixel positions.

@liuxuan30 Can you point out which part of the charts demo highlights a chart programmatically?

Alternatively, is there a way to show the currently selected entry in any other mechanism besides using highlighting?

This is absolutely essential for TVOS since Charts does not support the focus environment, and user interactions on the chart need to be handled programmatically instead of relying on the built in gesture recognizers.

To work around this issue I've done the following in my local copy:

In Highlight.swift, add an initializer that takes a y value as well:

    /// - parameter x: the x-value of the highlighted value
    /// - parameter y: the y-value of the highlighted value
    /// - parameter dataSetIndex: the index of the DataSet the highlighted value belongs to
    public init(x: Double, y: Double, dataSetIndex: Int)
    {
        _x = x
        _y = y
        _dataSetIndex = dataSetIndex
    }

Then when I want to programmatically highlight, I do it like so:

   let entry = //... the ChartDataEntry I want to highlight
   self.chart.highlightValue(
       Highlight(x: entry.x, y: entry.y, dataSetIndex: 0)
   )

I'm definitely not familiar enough with the code to know if this is decent approach to move forward with or not. If it is, I think one thing that would help is a ChartData.highlightForEntry() -> Highlight to act as an inverse to ChartData.entryForHighlight()

Actually, looking closer, I found that there were recent fixes to some of the other renderers that were not applied to Line charts.

In this commit:

https://github.com/danielgindi/Charts/commit/8905a46c8262998ccdb780bbd5d2c03e45b8ab5a#diff-52d760df99fc778bb8222bd3cc9ce413R225

The x and y variables were changed to come from the entry, not the Highlight h. I think if this same fix was applied to LineChartRenderer the issue would be fixed.

I'll try that out and hopefully get a PR for it ready today time permitting.

Also, it doesn't look like the y Value is actually used, since the highlight line just goes from contentTop to contentBottom. The root of the issue is actually that in this line:

let pt = trans.pixelForValues(x: x, y: y)

If y is NaN then pt.x comes out as NaN as well. This actually appears to be a Swift 3/CoreGraphics bug, as evidenced in the Swift Repl here:

  7> import CoreGraphics
  8> let trans = CGAffineTransform(scaleX: 1.0, y: 1.0)
trans: CGAffineTransform = {
  a = 1
  b = 0
  c = 0
  d = 1
  tx = 0
  ty = 0
}
  9> let pt = CGPoint(x: 1.0, y: Double.nan)
pt: CGPoint = (x = 1, y = NaN)
 10> pt.applying(trans)
$R2: CGPoint = (x = NaN, y = NaN)

@apurva can you try my fix-1495 branch here:

https://github.com/ryanschneider/Charts/tree/fix-1495

And see if it works as expected for you? It's working for me. @danielgindi & @liuxuan30, I more or less copied the code from ScatterChartRenderer but added the if x > chartXMax * animator.phaseX check which LineChartRenderer had.

I don't _think_ I need to be iterating over set.entriesForXValue(high.x) but currently am. I don't think there's harm since there should never be more than one entry, but if you can confirm that's the case I'll happily collapse that to a single set.entryForXValue(high.x) call and send a PR.

It'd also be nice to add a programmatic highlight option to the ChartsDemo to aid in regression testing highlight bugs, but I haven't investigated what it'd take to do that.

Thank you for your efforts @ryanschneider ! @danielgindi what you think?

@ryanschneider Thanks for your efforts. I tried the changes in your branch, but both the methods highlightValueWithX and highlightValueWithHighlight both still do not work for me. The y value of the highlight is still NaN and the highlight does not draw on the chart when called programmatically.

@danielgindi Just tested with the latest master, including your commit at https://github.com/danielgindi/Charts/commit/32a5952cae25f864c5fd3a449e4f413da7f36f9b

highlightValueWithX still does not show the highlight lines. The delegate gets fired and the y value of highlight is still NaN in the delegate. As the case earlier, highlighting via the gesture recognizers show the highlight lines, only not so when highlightValueWithX is called.

Still does not work.

Still not working for me in Swift 3.

`class ChartsViewController: UIViewController {

@IBOutlet var lineChartView: LineChartView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.

    let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
    let unitsSold = [20.0, 4.0, 6.0, 3.0, 12.0, 16.0]

    setChart(dataPoints: months, values: unitsSold)

}

func setChart(dataPoints: [String], values: [Double]) {

    var dataEntries: [ChartDataEntry] = []

    for i in 0..<dataPoints.count {
        let dataEntry = ChartDataEntry(x: Double(i), y: values[i])
        dataEntries.append(dataEntry)
    }

    let lineChartDataSet = LineChartDataSet(values: dataEntries, label: "Units Sold")
    let lineChartData = LineChartData(dataSet: lineChartDataSet)
    lineChartDataSet.highlightLineWidth = 2
    lineChartDataSet.highlightColor = UIColor.red

    lineChartView.data = lineChartData

    lineChartView.highlightValue(x: 3, dataSetIndex: 0)

    }

}`

Change this line: lineChartView.highlightValue(x: 3, dataSetIndex: 0)

to: lineChartView.highlightValue(Highlight(x: 3, y: 0, dataSetIndex: 0)

I tried specifying a y:0 on a line graph with multiple datasets and it still doesn't work. Is there any update on this? It's a pretty big bug.

I'm calling from Objective C.

Little hack to get the position of the highlighted value

// Highlight set programmatically
let dataEntry = dataEntries[linechartData.entryCount-1]
self.lineChartView.highlightValue(Highlight(x:` dataEntry.x, y:dataEntry.y, dataSetIndex: 0), callDelegate:` true)
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
        var markerPosition = CGPoint(x:highlight.xPx, y: highlight.yPx)
        // Hack to get the real position of the highlight programaticaly
        if markerPosition.x.isNaN || markerPosition.y.isNaN{
            let transformer = lineChartView.getTransformer(forAxis: lineChartView.leftAxis.axisDependency)
            let pt = transformer.pixelForValues(x: entry.x, y: entry.y)
            markerPosition.x = pt.x
            markerPosition.y = pt.y
        }
}

I tried your hack , jndefosse, but how can I call the function to show the labels only when entry is highlighted?

Is this bug fixed? I cannot seem to highlight a section in Pie Chart s of iOS 13.5 Swift 5.1

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brytnvmg picture brytnvmg  ·  4Comments

Shunshine07 picture Shunshine07  ·  3Comments

kwstasna picture kwstasna  ·  3Comments

BrandonShega picture BrandonShega  ·  4Comments

sjdevlin picture sjdevlin  ·  3Comments