patrykandpatrick / vico

A light and extensible chart library for Android.
https://patrykandpatrick.com/vico/wiki
Apache License 2.0
2.08k stars 125 forks source link

Line chart with only one value doesn't display long x value even when there is space for it #610

Closed rhult closed 6 months ago

rhult commented 6 months ago

How to reproduce

The following snippet shows the bug. The x value might need tweaking, but the following works for me in previews and on my device. I'm not sure if it depends on the resolution.

package com.skf.quickcollect.ui.assets.viewmeasurement.point

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.tooling.preview.Preview
import com.patrykandpatrick.vico.compose.axis.horizontal.rememberBottomAxis
import com.patrykandpatrick.vico.compose.axis.vertical.rememberStartAxis
import com.patrykandpatrick.vico.compose.chart.CartesianChartHost
import com.patrykandpatrick.vico.compose.chart.layer.rememberLineCartesianLayer
import com.patrykandpatrick.vico.compose.chart.layout.fullWidth
import com.patrykandpatrick.vico.compose.chart.rememberCartesianChart
import com.patrykandpatrick.vico.core.axis.AxisItemPlacer
import com.patrykandpatrick.vico.core.chart.layout.HorizontalLayout
import com.patrykandpatrick.vico.core.model.CartesianChartModel
import com.patrykandpatrick.vico.core.model.LineCartesianLayerModel

@Preview(widthDp = 400)
@Composable
fun Chart(
) {
    val entries = listOf(
// With only this value, there will be no x label shown
        LineCartesianLayerModel.Entry(x = 100000000, y = 1),
// Add this line, both value's labels will show:
//        LineCartesianLayerModel.Entry(x = 150000000, y = 1),
    )
    CartesianChartHost(
        chart = rememberCartesianChart(
            rememberLineCartesianLayer(),
            startAxis = rememberStartAxis(),
            bottomAxis = rememberBottomAxis(
                itemPlacer = remember {
                    AxisItemPlacer.Horizontal.default(
                        spacing = 1,
                        offset = 0,
                        addExtremeLabelPadding = true,
                    )
                }
            )
        ),
        model = CartesianChartModel(
            models = listOf(
                LineCartesianLayerModel.build {
                    series(
                        x = entries.map { it.x },
                        y = entries.map { it.y }
                    )
                },
            )
        ),
        horizontalLayout = HorizontalLayout.fullWidth(),
    )
}

Observed behavior

The x value is not visible, and no x line is shown. When adding in the second commented out value, both x values are shown in full.

I have also noticed that long x titles are ellipsized even when it is not necessary. In the snippet here, if setting the one x value to 10000000 (that is, one 0 less than the snippet), the title is displayed as "100000...", even though there is a lot of space left.

(I might need to implement my own item placer in the end, since I actually want to use a formatter that displays the value like "1 k", "1 M", "1 G" etc and I don't want to see more than one of each, which the builtin placer cannot do as far as I understand.)

Expected behavior

Charts with one value should ideally display the x value if it fits, and long x titles should not be ellipsized unless needed to leave space for other titles.

Vico version(s)

Latest unstable version

Android version(s)

13 and 14

Additional information

I'm using alpha 11.

rhult commented 6 months ago

I realized just after submitting that I can implement an AxisOverrider to make sure I always have a good range, and as the consumer of the API I probably have a better idea of what that would be since it is highly domain specific. I understand if you want to just close this issue.

shijunxing0130 commented 6 months ago

how

patrickmichalik commented 6 months ago

Hello! Both of these issues are caused by Float imprecision. We’ll be switching from Float to Double to make such problems less likely—all data types have their limits—but it should be possible to transform the chart data such that the x values are in a safe range and undo the transformation during formatting. The chart will then behave as expected:

Let me know if you have any questions about this. Regarding AxisItemPlacer.Horizontal.default, it always produces a constant x delta between labels, so for nonuniform spacing, a custom AxisItemPlacer.Horizontal implementation is needed. I’ll be closing this issue because the problem in question results not from a computational error in Vico but from how the Float data type works. The switch to Double is planned for Vico 2, so please keep an eye on the release notes.