Carson Moore Carson Moore - 5 months ago 78
Swift Question

How to constrain ios-chart to size of view

EDIT Short version:
I was displaying a graph using ios-charts with dynamic data, and it was chopping my graph off so the full vertical portion of the graph wasn't displayed properly. Certain actions (like transitioning from landscape to portrait or vice-versa) would cause the graph to be correctly displayed.

Original Question

I am displaying a line graph on iPhone 6 simulator running ios 9.3, using ios-charts version 2.2.4, and I'm running into a problem where the content gets vertically clipped... sometimes.

The chart is a drilldown chart, triggered by selecting a data point in another plot. For some data points, if I select them first, the drilldown chart gets clipped, like so:

Chart is clipped around 31 for some reason

However, if I select another data point first, then re-select this exact same datapoint that was just clipped, the chart renders more or less as expected:

Chart is not clipped and extends to ~66 as expected

I am manually setting the maximum Y value of the chart, and printing the maximum Y value confirms that it is indeed being set, so I am left to believe that the problem lies not in the chart formatting, but possibly in the way the chart constraints itself to the view? In other words, maybe this is a layout / storyboard issue and there is a property I can set on the view or even the parent view to make this render correctly?

Nonetheless, here is the code I use to generate the chart in case I'm doing anything obviously wrong:

... // Part where I actually get the data omitted bc its boring
let chartDataSet = LineChartDataSet(yVals: dataEntries, label: "")
let chartData = LineChartData(xVals: xVals, dataSet: chartDataSet) = chartData
formatChart(drilldownChart, yMax: [runningTotal, Double(].maxElement()!)
chartDataSet.colors = [UIColor.blackColor()]
chartDataSet.circleColors = [UIColor.blackColor()]
chartDataSet.drawCirclesEnabled = false
chartDataSet.drawFilledEnabled = true
chartDataSet.fillColor = UIColor.blackColor()
chartDataSet.fillAlpha = 1.0
chartDataSet.valueColors = dataPointLabelColors
print(drilldownChart.chartYMax) // Still prints 66, y'know, just in case

// Format a chart by eliminating grid lines, decimals, right axis, etc.
func formatChart(chart: BarLineChartViewBase, yMax: Double) {
let formatter = NSNumberFormatter()
formatter.minimumFractionDigits = 0
chart.xAxis.labelPosition = .Bottom
chart.xAxis.gridColor = UIColor.clearColor()
chart.leftAxis.axisMinValue = 0.0
chart.leftAxis.valueFormatter = formatter
chart.leftAxis.granularity = 1 // Sets a minimum granularity, but allows for higher granularities
chart.leftAxis.axisMaxValue = [1.0, yMax * 1.1].maxElement()!
chart.leftAxis.gridColor = UIColor.clearColor()
chart.rightAxis.enabled = false
chart.legend.enabled = false!.setValueFormatter(formatter)
if (!.xValCount > 20) {!.setDrawValues(false) }
chart.descriptionText = ""
chart.animate(xAxisDuration: 1.0, yAxisDuration: 1.0, easingOption: .Linear)
chart.pinchZoomEnabled = false
chart.doubleTapToZoomEnabled = false

let limit = ChartLimitLine(limit: Double(goal!.target), label: "")
limit.lineColor = UIColor.blackColor()
limit.lineDashLengths = [4.0, 2.0]
print(chart.leftAxis.axisMaxValue) // prints 66
print(chart.chartYMax) // Prints 66

EDIT Storyboard settings omitted because they are enormous and it turns out not relevant


The answer was to add a notifyDataSetChanged() to the end of the plot function.

Per this documentation I found on MPAndroid Chart (the Android version of ios-Charts),

notifyDataSetChanged(): Lets the chart know it's [sic] underlying data has changed and performs all necessary recalculations (offsets, legend, maxima, minima, ...). This is needed especially when adding data dynamically.