wuxudong / react-native-charts-wrapper

a react native charts wrapper (support android & iOS)
2.44k stars 658 forks source link

Highlights issue with marker not displaying #171

Closed GermanMontejo closed 6 years ago

GermanMontejo commented 6 years ago

Hi @wuxudong . I was trying to run your Example with the combined chart's highlights feature. But somehow the example app does not run and gives me the same error this guy is experiencing:

https://github.com/wuxudong/react-native-charts-wrapper/issues/159

I noticed one thing with the highlights feature. If my combinedchart data only has one bar, then the marker displays when the highlight is applied. but if the combined chart has 2 or more bars, then the marker does not display but the highlight is applied. I was trying to apply the highlight to the latest bar (the bar on the right most). Even though the bar got highlighted, the marker didn't appear above.

Note: the marker works if there's only one bar on the CombinedChart.

This is my highlights object:

[{"x":3.8000000715255737,"y":25,"dataIndex":1}]

The x here pertains to the latest bar, which is at index 3.8. The object shows that I have x, y, and dataIndex fields.

wuxudong commented 6 years ago

combined chart has 2 or more bars? Do you mean StackedBarChart?

GermanMontejo commented 6 years ago

no, sorry. let me give you a screenshot.

GermanMontejo commented 6 years ago

123

Do you see the small red bar there? There has to be a marker on top of it but somehow it does not show. If the 3rd and fourth bar are not in the combined chart, meaning we only have the first (tall, red) bar and the 2nd green bar then the marker appears on top of the tall red bar.

wuxudong commented 6 years ago

A gist link to a sample data will help.

GermanMontejo commented 6 years ago

okay, gimme a minute...

GermanMontejo commented 6 years ago

sorry for the late reply. this is my sample data for highlights: @wuxudong [{"x":3.8000000715255737,"y":25,"dataIndex":1}]

This is my sample data for the barData:

[{"x":0,"y":0,"marker":"."},{"x":1,"y":500,"marker":"!"},{"x":2,"y":0,"marker":"."},{"x":3,"y":25,"marker":"!"},{"x":4,"y":0,"marker":"."},{"x":5,"y":0,"marker":"."},{"x":6,"y":0,"marker":"."},{"x":7,"y":0,"marker":"."},{"x":8,"y":0,"marker":"."},{"x":9,"y":0,"marker":"."},{"x":10,"y":0,"marker":"."}}]

wuxudong commented 6 years ago

I have no idea why.

I update Examples->GroupBarChartScreen, and it works well. You can check out the latest example code.

simulator screen shot - iphone 6 - 2018-01-04 at 20 26 20

wuxudong commented 6 years ago

Float accuracy problem? 3.8 and 3.8000000715255737?

GermanMontejo commented 6 years ago

Hi! I'm not sure though. I'll try that when I get to the office tomorrow. Thanks for your help. Please don't close this issue yet.

On 4 Jan 2018 9:11 PM, "wuxudong" notifications@github.com wrote:

Float accuracy problem? 3.8 and 3.8000000715255737?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/wuxudong/react-native-charts-wrapper/issues/171#issuecomment-355278362, or mute the thread https://github.com/notifications/unsubscribe-auth/AHtgNhWTd_7lVA7SnsC-c7mZ_5-9Ti-Pks5tHM3ugaJpZM4RSsOx .

wuxudong commented 6 years ago

Another question, x is integer in your data. but you are using 3.8 in your highlight. It doesn't match any entry?

GermanMontejo commented 6 years ago

I have 2 bardata in my combinedchart and the reason they are side by side is because of the config object, where you can manipulate the bar space. But the combined chart is the one responsible for actually placing the exact x value for the bar. Even if I'm telling it to appear at let's say 7 (x = 7), the chart makes modifications where the x is really at 6.8 for the first bar, and 7.2 for the 2nd bar.

On 4 Jan 2018 9:21 PM, "wuxudong" notifications@github.com wrote:

Another question, x is integer in your data. but you are using 3.8 in your highlight. It doesn't match any entry?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/wuxudong/react-native-charts-wrapper/issues/171#issuecomment-355280357, or mute the thread https://github.com/notifications/unsubscribe-auth/AHtgNhFpMAWdXkh4LOl9moNo1SKwvCPkks5tHNA_gaJpZM4RSsOx .

wuxudong commented 6 years ago

But in highlight, I think you should use its original x.

GermanMontejo commented 6 years ago

If I use its original x, I.e. 7 instead of 6.8, the bar is not highlighted, the middle of the two bars get highlighted and a vertical yellow line appears (highlight indicator).

On 4 Jan 2018 9:44 PM, "wuxudong" notifications@github.com wrote:

But in highlight, I think you should use its original x.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/wuxudong/react-native-charts-wrapper/issues/171#issuecomment-355285364, or mute the thread https://github.com/notifications/unsubscribe-auth/AHtgNgTXSQTMPKQHeUzmYaSiqfm9GKBTks5tHNXQgaJpZM4RSsOx .

GermanMontejo commented 6 years ago

hi @wuxudong. You're right about the inaccurate floating point.

I've observed that the error happens with an unmatched x field.

entry: {"y":113,"x":4.799999713897705,"data":{"y":113,"x":4,"marker":"!"}}

^ That is the value for the bar that I clicked and the marker appeared when I clicked on the said bar.

This is the value of my x field for the highlight object:

[{"x":5,"y":113,"dataIndex":1}]

The reason why the marker does not display is because the x field of the highlight is not the same as the actual x value for the bar, which is at 4.79.

I can't just deduct .3 from x so that the highlight value would be at 4.7, because the actual x value of a bar varies depending on the number of bars in the chart. Yesterday, I had 3 bars, and deducting 0.2 for the highlight's x field worked, but today I have 5 bars and deducting 0.2 does not work because I need at least 0.3. If you can suggest a way to get the accurate value of the x field of a bar, it will be great! :)

because the only way I can get the accurate value is by tapping the said bar and it returns the actual x field in handleSelect().

GermanMontejo commented 6 years ago

@wuxudong can you modify highlights in such a way that it gets the rounded off value? like if i added 4.5676767680, it would accept the rounded off one decimal place, making 4.6 a match? Because there's no way I can get the accurate decimal places for the highlight's x value.

wuxudong commented 6 years ago

the code in MpAndroidChart CombinedData

public Entry getEntryForHighlight(Highlight highlight) {

    List<BarLineScatterCandleBubbleData> dataObjects = getAllData();

    if (highlight.getDataIndex() >= dataObjects.size())
        return null;

    ChartData data = dataObjects.get(highlight.getDataIndex());

    if (highlight.getDataSetIndex() >= data.getDataSetCount())
        return null;
    else {
        // The value of the highlighted entry could be NaN -
        //   if we are not interested in highlighting a specific value.

        List<Entry> entries = data.getDataSetByIndex(highlight.getDataSetIndex())
                .getEntriesForXValue(highlight.getX());
        for (Entry entry : entries)
            if (entry.getY() == highlight.getY() ||
                    Float.isNaN(highlight.getY()))
                return entry;

        return null;
    }
}

If you check the detail implementation of getEntriesForXValue(x), you will find exact match of x is needed. entry.getY() == highlight.getY() indicates that exact match of y is needed.

So exact x,y is need for highlight in CombinedChart.

Here is code in ChartData.

/**
 * Get the Entry for a corresponding highlight object
 *
 * @param highlight
 * @return the entry that is highlighted
 */
public Entry getEntryForHighlight(Highlight highlight) {
    if (highlight.getDataSetIndex() >= mDataSets.size())
        return null;
    else {
        return mDataSets.get(highlight.getDataSetIndex()).getEntryForXValue(highlight.getX(), highlight.getY());
    }
}

@Override
public T getEntryForXValue(float xValue, float closestToY) {
    return getEntryForXValue(xValue, closestToY, Rounding.CLOSEST);
}

getEntryForXValue(x,y)will find the closest (x,y), it can work in most case. But when you are using GroupedBarChart. MpAndroidChart/Charts is modifying x of data directly,

That means, the origin x:1 may be changed to x: 1.3/x:1.6/x:1.9, x:2 can be changed to x:2.3/x:2.6/x:2.9, then the closest x value to 2 is 1.9, that is not we want.

It is possible to caculated approximate x,y by some simple rules, and it will be harder to do it when using GroupBarChart in CombinedChart because exact value is needed.

It is the problem of underlying native library. The only workaround of default highlight of GroupBarChart is getting back the modified x/y.

If you really need it. It is ok to add commit here.

GermanMontejo commented 6 years ago

Yes, I've already told our project manager about the situation wherein the group bar chart will be the one deciding the actual x value for the bar and that I can't actually just put a number to be subtracted because the x value's decimal places change as the number of bars increase. Are you proposing that I open a ticket on the underlying library: charts and mpandroidcharts?

On 6 Jan 2018 11:50 AM, "wuxudong" notifications@github.com wrote:

the code in MpAndroidChart CombinedData

public Entry getEntryForHighlight(Highlight highlight) {

List<BarLineScatterCandleBubbleData> dataObjects = getAllData();

if (highlight.getDataIndex() >= dataObjects.size())
    return null;

ChartData data = dataObjects.get(highlight.getDataIndex());

if (highlight.getDataSetIndex() >= data.getDataSetCount())
    return null;
else {
    // The value of the highlighted entry could be NaN -
    //   if we are not interested in highlighting a specific value.

    List<Entry> entries = data.getDataSetByIndex(highlight.getDataSetIndex())
            .getEntriesForXValue(highlight.getX());
    for (Entry entry : entries)
        if (entry.getY() == highlight.getY() ||
                Float.isNaN(highlight.getY()))
            return entry;

    return null;
}

}

If you check the detail implementation of getEntriesForXValue(x), you will find exact match of x is needed. entry.getY() == highlight.getY() indicates that exact match of y is needed.

So exact x,y is need for highlight in CombinedChart.

Here is code in ChartData.

/**

  • Get the Entry for a corresponding highlight object
  • @param highlight
  • @return the entry that is highlighted */ public Entry getEntryForHighlight(Highlight highlight) { if (highlight.getDataSetIndex() >= mDataSets.size()) return null; else { return mDataSets.get(highlight.getDataSetIndex()).getEntryForXValue(highlight.getX(), highlight.getY()); } }

@Override public T getEntryForXValue(float xValue, float closestToY) { return getEntryForXValue(xValue, closestToY, Rounding.CLOSEST); }

getEntryForXValue(x,y)will find the closest (x,y), it can work in most case. But when you are using GroupedBarChart. MpAndroidChart/Charts is modifying x of data directly,

That means, the origin x:1 may be changed to x: 1.3/x:1.6/x:1.9, x:2 can be changed to x:2.3/x:2.6/x:2.9, then the closest x value to 2 is 1.9, that is not we want.

It is possible to caculated approximate x,y by some simple rules, and it will be harder to do it when using GroupBarChart in CombinedChart because exact value is needed.

It is the problem of underlying native library. The only workaround of default highlight of GroupBarChart is getting back the modified x/y.

If you really need it. It is ok to add commit here.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/wuxudong/react-native-charts-wrapper/issues/171#issuecomment-355720784, or mute the thread https://github.com/notifications/unsubscribe-auth/AHtgNps4tHZ4m6jIKihADYX3Jn0CFR6Rks5tHu10gaJpZM4RSsOx .

wuxudong commented 6 years ago

You should open a ticket there, but it might take a long time to be resolved.

A fast workaround is introducing a new getData api, just like we did in MovingWindowChartScreen.

componentDidMount() {
    this.refs.chart.getData().then(data -> {
        // this is the final data.
    })

}

the you can highlight exact entry you want.

GermanMontejo commented 6 years ago

Ahh, I see. By using that I'll be able to see the accurate x values of every bars in combinedchart? I'm only concerned about the bars...

On 6 Jan 2018 12:10 PM, "wuxudong" notifications@github.com wrote:

You should open a ticket there, but it might take a long time to be resolved.

A fast workaround is introducing a new getData api, just like we did in MovingWindowChartScreen.

componentDidMount() { let data = this.refs.chart.getData() // this is the final data. }

the you can highlight exact entry you want.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/wuxudong/react-native-charts-wrapper/issues/171#issuecomment-355721595, or mute the thread https://github.com/notifications/unsubscribe-auth/AHtgNshhFt2b-irg0c4ZNn-z7TUL1PHLks5tHvIcgaJpZM4RSsOx .

wuxudong commented 6 years ago

If you really need to highlight several entry in grouped bar chart, you can also do the grouping manually. You calculate every x it should be. That’s simple.

GermanMontejo commented 6 years ago

@wuxudong hi! I was trying to use this.refs.chart.getData().then(data => { })

But .getData() is undefined. I've also added the ref field in my CombinedChart component, but I still get undefined. this.refs.chart is fine, its type is object accdg. to typeof.

wuxudong commented 6 years ago

this.refs.chart.getData() is just a suggest. and the api is not implemented.

The simplest way is do the grouping by your self if you have to highlight. Just don't use the group config, treat it as common bar chart.

GermanMontejo commented 6 years ago

I don't know how that would work. The moment I pass the data to the values field, CombinedChart is the one that's going to decide what the value for the x field would be. I don't think I'll be able to calculate it since it could be .19900000 or .2000012121 or .180090900. I'll just talk to our manager and tell her this isn't possible as of now. I also don't think getData() is worth using as I'd have to fetch all data's x and y fields. Imagine having thousands of data for the chart and calling getData() when I have to highlight some bars (my data on the combined chart can also change depending on a user's selection), the app would be performing poorly.

wuxudong commented 6 years ago
data: {
  dataSets: [{
    values: [5, 40, 77, 81, 43],
    label: 'Company A',
    config: {
      drawValues: false,
      colors: [processColor('red')],
    }
  }, {
    values: [40, 5, 50, 23, 79],          
    label: 'Company B',
    config: {
      drawValues: false,
      colors: [processColor('blue')],
    }
  }, {
    values: [10, 55, 35, 90, 82],
    label: 'Company C',
    config: {
      drawValues: false,
      colors: [processColor('green')],
    }
  }],
  config: {
    barWidth: 0.2,
    group: {
      fromX: 0,
      groupSpace: 0.1,
      barSpace: 0.1,
    },
  }
}

will display similar to

data: {
  dataSets: [{
    values: [{x:0.2,y:5}, {x:1.2, y:40}, {x:2.2,y:77}, {x:3.2, y:81}, {x:4.2,y:43}],
    label: 'Company A',
    config: {
      drawValues: false,
      colors: [processColor('red')],
    }
  }, {
    values: [{x:0.4,y:40}, {x:1.4, y:5}, {x:2.4,y:50}, {x:3.4, y:23}, {x:4.4,y:79}],          
    label: 'Company B',
    config: {
      drawValues: false,
      colors: [processColor('blue')],
    }
  }, {
    values: [{x:0.6, y:10}, {x:1.6, y:55}, {x:2.6, y:35}, {x:3.6, y:90}, {x:4.6, y:82}],
    label: 'Company C',
    config: {
      drawValues: false,
      colors: [processColor('green')],
    }
  }],
  config: {
    barWidth: 0.2
  }
}

the group config is removed. you can do it at js side, and highlight is easy.

GermanMontejo commented 6 years ago

@wuxudong once again the day is saved, thanks to you! :1st_place_medal: Thanks for the tip! I'll just do some testing then close this issue, once everything is cleared, okay? Again, thanks for your help. :)

kenvandemar commented 6 years ago

Do you know how to keep highlight always display?