Meet “Y-Charts”: an Opensource Jetpack Compose chart library.

Codeangi
YML Innovation Lab
Published in
10 min readJul 13, 2023

Y-Charts is a Jetpack Compose-based charts/graphs library that enables developers to easily integrate various types of charts/graphs into their existing UI to visually represent statistical data. Jetpack Compose is Android’s recommended modern toolkit for building native UI. Y-Charts leverages on powerful features of Jetpack Compose to deliver accurate and accessible results for users, and many reusable components allow it to be concise and lightweight also enabling developers to customize and add new charts with ease.

Y-Charts Sample in action.

Adding Y-charts to your project.

You can add the library via Maven:

Charts in Y-Charts:

1. Cartesian Charts:

Cartesian charts, also known as coordinate charts or xy-charts, utilize a rectangular coordinate system with two perpendicular axes: the x-axis (horizontal) and the y-axis (vertical). These charts are particularly effective for displaying quantitative data and relationships between variables.

AxisData: The AxisData model supplied to each chart item controls the behavior and appearance of X and Y axis labels, user can opt for default behavior via the builder and can customize according to their needs.

  • Bar Charts: Bar charts use rectangular bars to represent data, where the length or height of each bar corresponds to its value.
    Y-Charts provides many customization including the orientation of the bar chart to achieve a horizontal-scroll behavior, along with grouping and stacking of bars. This enables users to visualize different types of bar charts with very few code changes. BarchartData and GroupBarChartData enable users to customize this behavior, additionally, users can change the appearance of the bars by using the BarStyle property. BarData represents the data for each bar shown in the chart. Following snippet shows the BarchartData declaration and usage of Barchart Composable.
data class BarChartData(
val chartData: List<BarData>,
val xAxisData: AxisData = AxisData.Builder().build(),
val yAxisData: AxisData = AxisData.Builder().build(),
val backgroundColor: Color = Color.White,
val horizontalExtraSpace: Dp = 0.dp,
val barStyle: BarStyle = BarStyle(),
val paddingEnd: Dp = 10.dp,
val paddingTop: Dp = 0.dp,
val tapPadding: Dp = 10.dp,
val showYAxis: Boolean = true,
val showXAxis: Boolean = true,
val accessibilityConfig: AccessibilityConfig = AccessibilityConfig(),
val barChartType: BarChartType = BarChartType.VERTICAL,
val drawBar: (DrawScope, BarData, Offset, Float, BarChartType, BarStyle) -> Unit = { drawScope, barChartData, drawOffset, height, barChartType, barStyle ->
//default implementation
drawBarGraph(drawScope, barChartData, drawOffset, height, barChartType, barStyle)
}
)

//usage

BarChart(modifier = Modifier.height(350.dp), barChartData = barChartData)
Various types/customizations of Barchart in Y-Charts Library in action
  • Line Charts: Line charts, also known as line graphs, are used to depict the relationship between two variables over a continuous interval or time. LineChartData Model provided in Y-Charts enables customization such as line color, line appearance etc. Line chart in Y-charts also supports multiple line charts to be drawn in a single graph.
data class LineChartData(
val linePlotData: LinePlotData,
val xAxisData: AxisData = AxisData.Builder().build(),
val yAxisData: AxisData = AxisData.Builder().build(),
val isZoomAllowed: Boolean = true,
val paddingTop: Dp = 30.dp,
val bottomPadding: Dp = 10.dp,
val paddingRight: Dp = 10.dp,
val containerPaddingEnd: Dp = 15.dp,
val backgroundColor: Color = Color.White,
val gridLines: GridLines? = null,
val accessibilityConfig: AccessibilityConfig = AccessibilityConfig()
)

//usage
LineChart(
modifier = Modifier
.fillMaxWidth()
.height(300.dp),
lineChartData = data
)
Linechart examples in the sample app.
  • Wave Charts: Wave charts, also referred to as waveform charts or waveform displays, are specialized visualizations used primarily in the field of signal processing and electronics. WaveChartData is the model used to customize Wave chart appearance and behavior, user can create a sine-wave chart and amplitude wave chart by using necessary values.
data class WaveChartData(
val wavePlotData: WavePlotData,
val xAxisData: AxisData = AxisData.Builder().build(),
val yAxisData: AxisData = AxisData.Builder().build(),
val isZoomAllowed: Boolean = true,
val paddingTop: Dp = 30.dp,
val bottomPadding: Dp = 10.dp,
val paddingRight: Dp = 10.dp,
val containerPaddingEnd: Dp = 15.dp,
val backgroundColor: Color = Color.White,
val gridLines: GridLines? = null,
val accessibilityConfig: AccessibilityConfig = AccessibilityConfig()
)

//usage
WaveChart(
modifier = Modifier
.fillMaxWidth()
.height(300.dp),
waveChartData = data
)
wave charts in sample app
  • Bubble Charts: Bubble charts are a variation of the scatter plot, where the data points are represented as bubbles or circles instead of simple dots. The bubbles’ size represents the value of a third variable, in addition to the x-axis and y-axis variables. BubbleChartData contains a list of bubbles, where each bubble is represented by Bubble model, Users can also set the maximum bubble radius to keep the bubble radius relative to supplied density value for each bubble.
data class BubbleChartData(
val bubbles: List<Bubble>,
val maximumBubbleRadius:Float = 100f,
val xAxisData: AxisData = AxisData.Builder().build(),
val yAxisData: AxisData = AxisData.Builder().build(),
val isZoomAllowed: Boolean = true,
val paddingTop: Dp = 30.dp,
val bottomPadding: Dp = 10.dp,
val paddingRight: Dp = 10.dp,
val containerPaddingEnd: Dp = 15.dp,
val backgroundColor: Color = Color.White,
val gridLines: GridLines? = null,
val accessibilityConfig: AccessibilityConfig = AccessibilityConfig()
)

//usage
BubbleChart(
modifier = Modifier
.fillMaxWidth()
.height(500.dp),
bubbleChartData = data
)
Bubblechart in the sample app.
  • Combined Charts: Combined charts, also known as combo charts, are visualizations that combine multiple chart types within a single graph. They allow for the simultaneous representation of different types of data or the comparison of multiple variables. In Y-Charts users can use CombinedChartData to implement Linechart and a Barchart on a single graph, where BarPlotData and LinePlotData determines the data set of Bar chart and Line chart respectively.
data class CombinedChartData(
val combinedPlotDataList: List<PlotData>,
val xAxisData: AxisData = AxisData.Builder().build(),
val yAxisData: AxisData = AxisData.Builder().build(),
val paddingTop: Dp = 30.dp,
val bottomPadding: Dp = 10.dp,
val paddingEnd: Dp = 10.dp,
val horizontalExtraSpace: Dp = 10.dp,
val containerPaddingEnd: Dp = 15.dp,
val backgroundColor: Color = Color.White,
val tapPadding: Dp = 10.dp,
val isZoomAllowed: Boolean = true,
val accessibilityConfig: AccessibilityConfig = AccessibilityConfig()
)
//usage
CombinedChart(
modifier = Modifier
.height(400.dp),
combinedChartData = combinedChartData
)
Combined charts in Y charts

2. Polar Charts:

Polar charts, also known as radial charts, utilize a polar coordinate system with a central point and radial axes. These charts are effective in representing cyclical or angular data, as well as comparing multiple variables around a central point.

  • Pie Charts: Pie charts are circular graphs divided into slices that represent different categories or proportions of a whole. Each slice’s size corresponds to the proportion it represents relative to the total.
    Users can implement Pie chart using PieChartData in Y-Charts, and can customize parameters such as slice portion, slice label and slice color.
    PieChartConfig is used to control the overall behavior and to customize labels being shown to represent the slices.
 PieChartData(val slices: List<Slice>, override val plotType: PlotType)
//configuring piechart
data class PieChartConfig(
val startAngle: Float = DEFAULT_START_ANGLE,
val showSliceLabels: Boolean = true,
val sliceLabelTextSize: TextUnit = DEFAULT_SLICE_LABEL_TEXT_SIZE.sp,
val sliceLabelTextColor: Color = Color.White,
val sliceLabelTypeface: Typeface = Typeface.DEFAULT,
val isAnimationEnable: Boolean = false,
@IntRange(from = 1) val animationDuration: Int = 500,
val strokeWidth: Float = DEFAULT_STROKE_WIDTH,
val labelFontSize: TextUnit = 24.sp,
val labelTypeface: Typeface = Typeface.DEFAULT,
val labelVisible: Boolean = false,
val labelType: LabelType = LabelType.PERCENTAGE,
val labelColor: Color = Color.White,
val labelColorType: LabelColorType = LabelColorType.SPECIFIED_COLOR,
val backgroundColor: Color = Color.White,
val activeSliceAlpha: Float = .8f,
val inActiveSliceAlpha: Float = 1f,
val isEllipsizeEnabled: Boolean = false,
val sliceMinTextWidthToEllipsize: Dp = 80.dp,
val sliceLabelEllipsizeAt: TextUtils.TruncateAt = TextUtils.TruncateAt.END,
val chartPadding: Int = DEFAULT_PADDING,
val accessibilityConfig: AccessibilityConfig = AccessibilityConfig(
chartDescription = PieChartConstants.DESCRIPTION
),
val isSumVisible: Boolean = false,
val sumUnit: String = "",
val isClickOnSliceEnabled: Boolean = true
)

//usage
PieChart(
modifier = Modifier
.fillMaxWidth()
.height(500.dp),
pieChartData,
pieChartConfig
) { slice ->
}
piecharts in Y charts
  • Donut Charts: Donut charts are similar to pie charts in terms of their purpose and usage. However, donut charts have a hole in the center. Similar to Pie Charts, users can customize overall appearance of the chart using the PieChartConfig and each slice can be customized using the Slice objects supplied as a list to PieChartData.
PieChartData(val slices: List<Slice>, override val plotType: PlotType)
//configuring piechart
data class PieChartConfig(
val startAngle: Float = DEFAULT_START_ANGLE,
val showSliceLabels: Boolean = true,
val sliceLabelTextSize: TextUnit = DEFAULT_SLICE_LABEL_TEXT_SIZE.sp,
val sliceLabelTextColor: Color = Color.White,
val sliceLabelTypeface: Typeface = Typeface.DEFAULT,
val isAnimationEnable: Boolean = false,
@IntRange(from = 1) val animationDuration: Int = 500,
val strokeWidth: Float = DEFAULT_STROKE_WIDTH,
val labelFontSize: TextUnit = 24.sp,
val labelTypeface: Typeface = Typeface.DEFAULT,
val labelVisible: Boolean = false,
val labelType: LabelType = LabelType.PERCENTAGE,
val labelColor: Color = Color.White,
val labelColorType: LabelColorType = LabelColorType.SPECIFIED_COLOR,
val backgroundColor: Color = Color.White,
val activeSliceAlpha: Float = .8f,
val inActiveSliceAlpha: Float = 1f,
val isEllipsizeEnabled: Boolean = false,
val sliceMinTextWidthToEllipsize: Dp = 80.dp,
val sliceLabelEllipsizeAt: TextUtils.TruncateAt = TextUtils.TruncateAt.END,
val chartPadding: Int = DEFAULT_PADDING,
val accessibilityConfig: AccessibilityConfig = AccessibilityConfig(
chartDescription = PieChartConstants.DESCRIPTION
),
val isSumVisible: Boolean = false,
val sumUnit: String = "",
val isClickOnSliceEnabled: Boolean = true
)

DonutPieChart(
modifier = Modifier
.width(100.dp)
.height(100.dp),
data,
firstPieChartConfig
) { slice ->}
Donut-charts demo in Y-Charts sample app

Developing/Customizing Y-Charts.

Reusable Components of Y-Charts.

In cartesian charts or XY-Charts, the charts are drawn based on the coordinates represented by X and Y. In Y-Charts, we have a reusable ScrollableCanvasContainer which helps us draw coordinates, a grid, and the axis itself, it also allows users to customize their appearance and behavior according to their needs. Some of the other reusable components include

  1. ScrollableCanvasContainer: ScrollableCanvasContainer is a container used to draw any graph which supports scroll, zoom, tap, or drag gestures. This composable is used to draw the chart background, to draw the axis, and the chart itself. developers can reuse or customize the appearance of the chart by changing the Modifier and various user interactions can be addressed by the callbacks provided such as onScroll.
ScrollableCanvasContainer(
modifier: Modifier,
calculateMaxDistance: DrawScope.(Float) -> Float,
onDraw: DrawScope.(Float, Float) -> Unit,
drawXAndYAxis: @Composable BoxScope.(Float, Float) -> Unit,
containerBackgroundColor: Color = Color.White,
layoutDirection: LayoutDirection = LayoutDirection.Ltr,
onPointClicked: (Offset, Float) -> Unit = { _, _ -> },
isPinchZoomEnabled: Boolean = true,
onScroll: () -> Unit = {},
onZoomInAndOut: () -> Unit = {},
scrollOrientation: Orientation = Orientation.Horizontal
)
  1. XAxis: XAxis compose method used for drawing xAxis in any given graph. Along with the Modifier, the xAxisData parameters enables developers to extensively customize Xaxis being displayed, AxisData is another re-usable model used to customize both the axis appearance and behavior, the following snippet shows the other customizations offered by xAxis composable.
@Composable
fun XAxis(
xAxisData: AxisData,
modifier: Modifier,
xStart: Float,
scrollOffset: Float,
zoomScale: Float,
chartData: List<Point>,
axisStart: Float
)
  1. YAxis: YAxis compose method used for drawing yAxis in any given graph. similar to xAxis, the Modifier, and the yAxisData parameters enable developers to extensively customize Yaxis being displayed, other customizable options are shown in following snippet.
@Composable
fun YAxis(
modifier: Modifier,
yAxisData: AxisData,
scrollOffset: Float = 0f,
zoomScale: Float = 0f,
chartData: List<Point> = emptyList(),
dataCategoryWidth: Float = 0f,
yStart: Float = 0f,
barWidth: Float = 0f
)
  1. AccessibilityBottomSheetDialog: The bottom sheet dialog appears when the accessibility-talk-back option is enabled in the phone settings.
    The bottom sheet shows items in a vertical list view with a close button at the top.
AccessibilityBottomSheetDialog is shown for a line chart when accessibility talk-back is enabled.
  1. Legends: Chart legends are a crucial component of data visualization that provides information about the various colors, attributes, symbols, and data points used in a chart. “Legends” is a composable re-usable component, which renders the list of legends in a grid format for the given grid column count, LegendsConfig along with the Modifier enables users to customize the appearance.
@Composable
fun Legends(modifier: Modifier = Modifier, legendsConfig: LegendsConfig)

Compose Multiplatform and Y-Charts

Compose Multiplatform is a modern UI declarative framework by JetBrains, based on Kotlin Multiplatform and Jetpack Compose, a modern UI toolkit for building native Android applications. Compose Multiplatform enables the development of cross-platform libraries that can be used across Android and iOS. By utilizing Compose Multiplatform, Y-Charts can share common code logic, data models, and rendering components across platforms. This approach streamlines the development process, reduces duplication of efforts, and ensures a consistent user experience across different platforms. Developers can easily create interactive and visually appealing charts by leveraging the declarative nature and powerful ability of Jetpack Compose.

kmm-ycharts is a dedicated repository for the Kotlin Multiplatform version of the Ycharts Android library.

Opensource Contributors:

1. @kikoso:Enrique López Mañas
2. @dkk009: Deepak KK
3. @Margin-KS
4. @sreekuttan-yml: Sreekuttan
5. @preetham1316: Preetham Ivan Dsouza
6. @alexandre-thauvin: Alexandre Thauvin
7. @Codeangi: Ananthakrishna
8. @HKIRA00: Harsha Kiran
9. @krishanjangir-yml: Krishan Jangir
10. @jay607: Jay Challa
11. @xyzwilliamxyz: William

--

--