【Kotlin/Android】MPAndroidChartでグラフを実装する方法!
この記事からわかること
- Android Studio/KotlinでMPAndroidChartを使用したグラフの実装方法
- 棒グラフや折れ線グラフの実装方法
- 機能やデザインを設定するには?
- ポインタをアイコンに変更するには?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Android Studio:Flamingo
- Kotlin:1.8.20
MPAndroidChartとは?
MPAndroidChartはAndroidアプリで簡単に折れ線グラフや円グラフ、棒グラフなどの図を実装することのできるライブラリです。MPAndroidChart自体はJavaで開発されているようですが、Kotlinと互換性があるのでどちらの言語でも問題なく機能を利用することが可能です。
またMPAndroidChart
はiOSのDGCharts
と同じ開発者であり、基本的な操作やAPIなども比較的同じように実装されているようでした。
導入方法
Android StudioでMPAndroidChartを使用するためには「settings.gradle」に maven { url 'https://jitpack.io' }
を追加します。
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// MPAndroidChart
maven { url 'https://jitpack.io' }
}
}
続いて「build.grade(Module)」にimplementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
を追加します。。
dependencies {
// MPAndroidChart
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}
折れ線グラフの実装方法
MPAndroidChartを使用して折れ線グラフを実装してみます。どのグラフでも基本的に以下の流れでグラフを作成していきます。
MPAndroidChartでグラフを実装する流れ
- レイアウトファイルにViewを追加
- 元データの準備
- 元データをEntry型に変換したリストを準備
- グラフ線やポインタなどの機能、デザインなどを設定
- ラベルやグラフなどの機能、デザインなどを設定
- グラフのデータに格納
まずはレイアウトファイルにViewを追加します。折れ線グラフであればcom.github.mikephil.charting.charts.LineChart
になります。
<!-- ①折れ線グラフ -->
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/lineChart"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_margin="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
続いてグラフに表示させるためのデータをFloat
型で用意し、X軸とY軸に表示させる値を定義するEntry
型の配列を作成し、LineChart
のdata
プロパティに設定すればグラフが表示されるようになります。
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
class MainActivity : AppCompatActivity() {
// ②元データの準備
private val data: List<Float> = listOf(100.0f, 65.0f, 90.0f, 30.0f, 45.0f)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var lineChart: LineChart = findViewById(R.id.lineChart)
// ③元データをEntry型に変換したリストを準備
val dataEntries = mutableListOf<Entry>()
data.forEachIndexed { index, value ->
// X軸は配列のインデックス番号
val dataEntry = Entry(index.toFloat(), value)
dataEntries.add(dataEntry)
}
// ④グラフ線やポインタなどの機能、デザインなどを設定
val lineDataSet = LineDataSet(dataEntries, "グラフ名")
// グラフの線の太さ
lineDataSet.lineWidth = 5.0f
// ⑤ラベルやグラフなどの機能、デザインなどを設定
// x軸のラベルをbottomに表示
lineChart.xAxis.position = XAxis.XAxisPosition.BOTTOM
// x軸のラベル数をデータの数にする
lineChart.xAxis.labelCount = dataEntries.size - 1
// ⑥グラフのデータに格納
lineChart.data = LineData(lineDataSet)
}
}
グラフのデザインを変更する
グラフのデザインを変更するにはLineDataSet
のプロパティを操作します。
// グラフの線の太さ
lineDataSet.lineWidth = 5.0f
// グラフモード(曲線)
lineDataSet.mode = LineDataSet.Mode.CUBIC_BEZIER
// グラフの色
lineDataSet.colors = listOf(Color.BLACK)
// 点の色
lineDataSet.circleColors = listOf(Color.RED)
// 点の大きさ
lineDataSet.circleRadius = 5.0f
// 塗りつぶし
lineDataSet.setDrawFilled(true)
// 値非表示
lineDataSet.setDrawValues(false)
// ポインタ非表示
lineDataSet.setDrawCircles(true)
グラフ自体の機能を設定する
デフォルトではグラフの点をタップするとフォーカスが写ったり、ピンチやダブルタップでズームできるようになっています。これらを無効にするにはLineChart
のプロパティを操作します。
他にもデータ数が多い場合に一部分だけを最初にズームした状態にするためのsetVisibleXRangeMaximum
などがあります。※印がついている設定はlineChart.data
プロパティにデータを格納した後でないと動作しないので注意してください。
// データがない場合のテキスト
lineChart.setNoDataText("データがありません")
// タップでの点の選択を無効
lineChart.isHighlightPerTapEnabled = false
// ピンチでのズームを無効
lineChart.setPinchZoom(false)
// データの最大表示範囲を制限 (データ数が多い場合横にスクロールで表示エリアを移動可能)
lineChart.setVisibleXRangeMaximum(10f) // ※
// データの最小表示範囲を制限 (データ数が多い場合横にスクロールで表示エリアを移動可能)
lineChart.setVisibleXRangeMinimum(5f) // ※
// データの表示位置を指定したX軸の値にする(インデックスではなくX軸の値を指定)
lineChart.moveViewToX((data.size - 1).toFloat()) // ※
// 選択したX軸の位置をハイライト表示
lineChart.highlightValue(5f,0) // ※
// 表示されているデータの一番低い値を取得
lineChart.lowestVisibleX
// 表示されているデータの一番高い値を取得
lineChart.highestVisibleX
// ダブルタップでのズームを無効
lineChart.isDoubleTapToZoomEnabled = false
// グラフアニメーション
lineChart.animateXY(1, 1)
// グラフUI全体の背景色を変更
lineChart.setBackgroundColor(Color.TRANSPARENT)
// グラフ描画エリアの背景色を変更
lineChart.setDrawGridBackground(true)
lineChart.setGridBackgroundColor(Color.WHITE)
// グラフ描画エリアの枠線を描画
lineChart.setDrawBorders(true)
lineChart.setBorderColor(Color.WHITE)
lineChart.setBorderWidth(2f)
またanimateプロパティを設定することでグラフ描画時にアニメーションがついて描画されます。
ラベルのカスタマイズ
グラフに表示しているラベルをカスタマイズするにはLineChart
のプロパティを操作します。
// 右下のDescription Labelを非表示
lineChart.description.isEnabled = false
// グラフ名ラベルを非表示
lineChart.legend.isEnabled = false
// Y軸右側ラベルを非表示
lineChart.axisRight.isEnabled = false
// y左軸最大値
lineChart.axisLeft.axisMaximum = 100f
// y左軸最小値
lineChart.axisLeft.axisMinimum = 0f
// y軸ラベルの表示個数
lineChart.axisLeft.labelCount = 10
// 上からのオフセット
lineChart.extraTopOffset = 30f
データのポインタを画像(Image)にする
データのポインタを画像(Image)に変更するにはEntry(float x, float y, Drawable icon)
を使用します。
var icon: Drawable? = ResourcesCompat.getDrawable(getResources(), R.drawable.android, null)
val dataEntry = Entry(key.toFloat(), value.toFloat(), icon)
明示的にアイコン表示しないようにするにはsetDrawIcons
にfalse
を指定します。
// アイコンを非表示にする
lineDataSet.setDrawIcons(false)
一度に表示するデータ数が多い場合は非表示になってしまうのでsetMaxVisibleValueCount
で明示的に表示させたい個数を指定することができます。デフォルト値は100
です。
// 表示するデータ値数を指定
lineChart.setMaxVisibleValueCount(200)
自分で用意した画像を使用する際は大きさを変更しないとグラフのポインタのサイズを大幅にズレてしまうので画像をリサイズして使用します。
val icon: Drawable? = ResourcesCompat.getDrawable(getResources(), R.drawable.myImage, null)
val bitmap = (icon as BitmapDrawable).bitmap
val resizeDrawable = BitmapDrawable(resources, Bitmap.createScaledBitmap(bitmap, 40, 40, true))
val dataEntry = Entry(value.first, value.second, resizeDrawable)
タップした際にデータを取得する
表示されているグラフでタップした箇所のデータを取得するにはsetOnChartGestureListener
メソッドにOnChartGestureListener
型のオブジェクトを渡し各メソッドからタップなどのジェスチャーでMotionEvent型で情報を取得することが可能になります。
// Chartのリスナーを設定します
lineChart.setOnChartGestureListener(object : OnChartGestureListener {
override fun onChartGestureStart(me: MotionEvent?, lastPerformedGesture: ChartTouchListener.ChartGesture?) {
// タッチジェスチャーが開始された際の処理
}
override fun onChartGestureEnd(me: MotionEvent?, lastPerformedGesture: ChartTouchListener.ChartGesture?) {
// タッチジェスチャーが終了した際の処理
}
override fun onChartLongPressed(me: MotionEvent?) {
// 長押しされた際の処理
}
override fun onChartDoubleTapped(me: MotionEvent?) {
// ダブルタップされた際の処理
}
override fun onChartSingleTapped(me: MotionEvent?) {
// シングルタップされた際の処理
// タップされた位置にあるデータを取得してみる
val highlight = lineChart.getHighlightByTouchPoint(me?.x ?: 0f, me?.y ?: 0f)
if (highlight != null) {
val entry = lineChart.data.getDataSetByIndex(highlight.dataSetIndex).getEntryForIndex(highlight.x.toInt())
Log.e("------", entry.x.toString())
}
}
override fun onChartFling(me1: MotionEvent?, me2: MotionEvent?, velocityX: Float, velocityY: Float) {
// フリックされた際の処理
}
override fun onChartScale(me: MotionEvent?, scaleX: Float, scaleY: Float) {
// ズームされた際の処理
}
override fun onChartTranslate(me: MotionEvent?, dX: Float, dY: Float) {
// 移動された際の処理
}
})
グラフをリセットする
グラフに表示しているデータをリセットしたい場合はclearValues
メソッドとclear
メソッドを使用します。これでグラフの設定も初期化されnotifyDataSetChanged
でデータの変更をUIへと反映させinvalidate
で再描画をさせています。
lineChart.data?.clearValues()
lineChart.clear()
lineChart.notifyDataSetChanged()
lineChart.invalidate()
実際に使用して開発したアプリのソースコードを公開中
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。