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

LineChart X-Axis - How To Always Display First & Last Label #2006

Open
cnowak7 opened this issue Dec 26, 2016 · 23 comments
Open

LineChart X-Axis - How To Always Display First & Last Label #2006

cnowak7 opened this issue Dec 26, 2016 · 23 comments
Labels

Comments

@cnowak7
Copy link

cnowak7 commented Dec 26, 2016

In my Line Chart, I have it set up so that if there's only one data entry, I make the data point show up in the middle like this:

screen shot 2016-12-25 at 7 00 36 pm

If there's more data entries, it'll look more like this:

screen shot 2016-12-25 at 7 00 50 pm

The problem I'm having is that the last label on the X-Axis is not showing up. This is data from the past 30 days, so I'd like the last label, Dec 25, to show up. Is there a way to make my Line Chart always display the first and last label on the X-Axis? I don't care how it computes or skips the labels in between.

@liuxuan30
Copy link
Member

liuxuan30 commented Dec 28, 2016

try avoidFirstLastClippingEnabled, default is false.

    /// if set to true, the chart will avoid that the first and last label entry in the chart "clip" off the edge of the chart
    open var avoidFirstLastClippingEnabled = false

@vaibhav-varshaaweblabs
Copy link

@cnowak7 Were you able to solve the issue mentioned in the 2nd image? Please share the solution

@vaibhav-varshaaweblabs
Copy link

avoidFirstLastClippingEnabled does not help. The last label always gets cut

@ondrejhanslik
Copy link

If I look into the source code, the axis entries are calculated in AxisRendererBase.computeAxisValues and there is no way to enforce the max value to be displayed. I believe this functionality was supported in the previous version though.

@liuxuan30
Copy link
Member

#2007 seems same issue with this one?
@ondrejhanslik by default, computeAxisValues() will take min and max value to calculate the range. So the min and max value should be larger than the data's min/max value to hold all the data. Have you checked what's your min/max value in computeAxisValues(), and what's your data's min/max value?

@vaibhav-varshaaweblabs
Copy link

@liuxuan30 I use custom String array as X-Axis Values i.e. Dates

@vaibhav-varshaaweblabs
Copy link

Here's a screenshot of my chart

untitled

@cnowak7
Copy link
Author

cnowak7 commented Dec 29, 2016

This is how my chart looks when setting avoidFirstLastClippingEnabled to true:

screen shot 2016-12-28 at 11 02 15 pm

Here's some extra code that I'm using to set up my X-Axis:

private func setUpLineChartPreferences() {
        .
        .
        .
        // x-axis
        self.lineChart.xAxis.labelPosition = .bottom
        self.lineChart.xAxis.drawGridLinesEnabled = true
        self.lineChart.xAxis.granularity = 1.0
        .
        .
        .
}
private func setUpLineChart(withDataEntries entries: [ChartDataEntry]) {
        let entryCount = entries.count
        if entryCount > 0 {
            let dataSet = LineChartDataSet(values: entries, label: nil)
            dataSet.drawFilledEnabled = true
            dataSet.fillColor = .green
            dataSet.circleRadius = 5
            dataSet.drawValuesEnabled = false
            dataSet.setColor(.black)
            dataSet.highlightColor = .green
            dataSet.setCircleColor(.blue)
            let lineChartData = LineChartData(dataSet: dataSet)
            self.lineChart.data = lineChartData
            // SET UP X-AXIS
            self.lineChart.xAxis.valueFormatter = IndexAxisValueFormatter(values: self.chartLabels)
            self.lineChart.xAxis.avoidFirstLastClippingEnabled = true
            print("NOWAK: CHART LABELS THO - \(self.chartLabels)")
            if entryCount == 1 {
                self.lineChart.xAxis.axisMinimum = -1.0
                self.lineChart.xAxis.axisMaximum = 1.0
            } else {
                self.lineChart.xAxis.axisMinimum = 0.0
                self.lineChart.xAxis.axisMaximum = Double(self.chartLabels.count - 1)
            }
            print("X MIN IS \(self.lineChart.xAxis.axisMinimum) AND X MAX IS \(self.lineChart.xAxis.axisMaximum)")
        } else {
            self.lineChart.noDataText = "No Stats For The Past \(self.currentFilter.capitalized)"
            self.lineChart.setNeedsDisplay()
        }
        switch self.currentFilter {
        case "week":
            self.weekFilterButton.backgroundColor = .blue
            self.monthFilterButton.backgroundColor = .darkGray
            self.yearFilterButton.backgroundColor = .darkGray
        case "month":
            self.monthFilterButton.backgroundColor = .blue
            self.weekFilterButton.backgroundColor = .darkGray
            self.yearFilterButton.backgroundColor = .darkGray
        case "year":
            self.yearFilterButton.backgroundColor = .blue
            self.weekFilterButton.backgroundColor = .darkGray
            self.monthFilterButton.backgroundColor = .darkGray
        default:
            print("ERROR SETTING FILTER BUTTON BACKGROUND COLORS")
        }
        self.stopLoading()
}

@cnowak7
Copy link
Author

cnowak7 commented Dec 29, 2016

I am using Charts 3.0.1 by the way :)

@vaibhav-varshaaweblabs
Copy link

Same here. Charts 3.0.1, XCode 8.0 and Swift 3.0

@cnowak7
Copy link
Author

cnowak7 commented Dec 29, 2016

If a solution isn't possible for this situation, I guess a workaround that would probably make sense would be to, when the chart is displayed, highlight the last value (today) so that the "BalloonMarker" shows up displaying the text "Dec XX\n500".

@cnowak7
Copy link
Author

cnowak7 commented Dec 29, 2016

On my side obviously :)

@liuxuan30 liuxuan30 added the bug label Dec 29, 2016
@liuxuan30
Copy link
Member

liuxuan30 commented Dec 29, 2016

OK I checked it.

In chart 3.0, x axis behaves like y axis, so you can check out your y axis labels, the biggest y axis label is smaller than data's max value, in
image

In computeAxisValues(), it reads min and max value from the axis min/max value( which is the data's min/max value) and calculates an interval to get the x axis labels.

For example in ChartsDemo - Line Chart Dual YAxis, if my x values are from 0 to 20,
computeAxisValues() takes 0, 20 as min/max value, then, my labelCount is 6 by default, it will calculates rawInterval = (max - min) / labelCount, and later the final interval will be 3. Then it starts from 0, to get 7(labelCount + 1) labels, which are 0,3,6,9,12,15,18. The x axis labels last one is 18, not 20.

The reason isAvoidFirstLastClippingEnabled does not work is because it handles when the last label is out of bound, so it's irrelevant to this issue.

If you want to sure the label that is your data's x value, you have to tweak computeAxisValues() to return the labels. Just check out computeAxisValues() to see the details and you should be able to change it.

@danielgindi what you do think for such user cases?

@ondrejhanslik
Copy link

ondrejhanslik commented Dec 29, 2016

@liuxuan30 We don't want to tweak computeAxisValues to return some specific labels. For example, when I am displaying a chart over dates (e.g. x-values are days of a week, days of a month or months of a year), I need the first and last labels to be displayed (e.g. Monday and Sunday or 1/1 and 31/1).

I first generate the formatted values (e.g. day names or formatted days) and then set them as:

    xAxis.axisMinimum = 0
    xAxis.axisMaximum = Double(xValues.count - 1)
    xAxis.valueFormatter = IndexAxisValueFormatter(values: xValues)

What I need is a smarter computeAxisValues that will always display the first label and the last label and then will calculate the labels between them.

This is a very basic and very common use case.

@liuxuan30
Copy link
Member

liuxuan30 commented Dec 29, 2016

I understand. There are still bugs about the x axis labels, e.g. label overlap.
Current logic is first knowing the min/max value, and generate intervals from it and accumulate to get the axis labels. However current computeAxisValues() does not guarantee the max value / last label is xAxis.axisMaximum. That's what I need @danielgindi's input about this.

Maybe I should use 'override' rather than 'tweak' for computeAxisValues(). You can provide an implementation to make sure your first/last value is always displayed as workaround. However, this might cause the label out of bound or other issues.

Another way is, you can try setLabelCount(count, forceLabelEnabled) equals your x values count or half to see the result.
The logic is quite diffrent then:

        // force label count
        if axis.isForceLabelsEnabled
        {
            interval = Double(range) / Double(labelCount - 1)
            
            // Ensure stops contains at least n elements.
            axis.entries.removeAll(keepingCapacity: true)
            axis.entries.reserveCapacity(labelCount)
            
            var v = yMin
            
            for _ in 0 ..< labelCount
            {
                axis.entries.append(v)
                v += interval
            }
            
            n = labelCount
        }

It does not involves the addtional process, just simple math.

@vaibhav-varshaaweblabs
Copy link

@liuxuan30 What if the x-axis values are in String format? In my case, the x-axis values are Dates in String format

@liuxuan30
Copy link
Member

liuxuan30 commented Jan 3, 2017

@vaibhav-varshaaweblabs x axis now is taking double ONLY in Chart 3.x, so you can use valueFormatter to display the label instead of the double. However, the valueFormatter might be complicated, when you need to consider zooming/scrolling

@raudabaugh
Copy link

raudabaugh commented Jul 9, 2017

Has anyone found a solution for this in Charts 3.0.2? I'm using date strings for my x-axis labels and seeing the last label disappear occasionally, but having trouble reproducing. This is with isAvoidFirstLastClippingEnabled set to true. I'm wondering if this could be related to #2563?

@muddanaraj
Copy link

@vaibhav-varshaaweblabs @raudabaugh : How did u guys manage to plot strings on the X-Axis, as the setDataCount method is expecting int or double values for X and Y.
Kindly let me know, thanks in advance

@tanvi12
Copy link

tanvi12 commented May 11, 2019

bottomAxis.setLabelCount(entries.size(), true); and also set margin right to make visible last count.

@anveshfactorly
Copy link

    lineChart?.xAxis.setLabelCount(arrOfMonth.count, force: true)

This will help for display last value of line chart - i tried and worked for me

@danielerne
Copy link

setLabelCount does not work if there are many x values.
Ist there still no solution for displaying the last label?

@Rajneesh071
Copy link

Rajneesh071 commented Dec 15, 2021

After doing
xAxis.setLabelCount(arrOfMonth.count, force: true)
I am seeing that there is no animation on xAxis labels while scaling and translation. Labels are fixed.
How to add animation ?
@liuxuan30

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

No branches or pull requests

10 participants