feat: normalize genres
This commit is contained in:
parent
5218d5cd28
commit
db979de829
2 changed files with 117 additions and 45 deletions
|
@ -18,7 +18,6 @@ import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAScrollablePlotAre
|
||||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAStyle
|
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAStyle
|
||||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAYAxis
|
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAYAxis
|
||||||
import com.github.aachartmodel.aainfographics.aatools.AAColor
|
import com.github.aachartmodel.aainfographics.aatools.AAColor
|
||||||
import com.github.aachartmodel.aainfographics.aatools.AAGradientColor
|
|
||||||
|
|
||||||
class ChartBuilder {
|
class ChartBuilder {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -37,7 +36,7 @@ class ChartBuilder {
|
||||||
data class ChartPacket(
|
data class ChartPacket(
|
||||||
val username: String,
|
val username: String,
|
||||||
val names: List<Any>,
|
val names: List<Any>,
|
||||||
val statData: List<Number>
|
var statData: List<Number>
|
||||||
)
|
)
|
||||||
|
|
||||||
fun buildChart(
|
fun buildChart(
|
||||||
|
@ -47,11 +46,12 @@ class ChartBuilder {
|
||||||
statType: StatType,
|
statType: StatType,
|
||||||
mediaType: MediaType,
|
mediaType: MediaType,
|
||||||
chartPackets: List<ChartPacket>,
|
chartPackets: List<ChartPacket>,
|
||||||
xAxisName: String = "X Axis",
|
xAxisName: String,
|
||||||
xAxisTickInterval: Int? = null,
|
xAxisTickInterval: Int? = null,
|
||||||
polar: Boolean = false,
|
polar: Boolean = false,
|
||||||
passedCategories: List<String>? = null,
|
passedCategories: List<String>? = null,
|
||||||
scrollPos: Float? = null,
|
scrollPos: Float? = null,
|
||||||
|
normalize: Boolean = false
|
||||||
): AAOptions {
|
): AAOptions {
|
||||||
val typedValue = TypedValue()
|
val typedValue = TypedValue()
|
||||||
context.theme.resolveAttribute(
|
context.theme.resolveAttribute(
|
||||||
|
@ -69,6 +69,11 @@ class ChartBuilder {
|
||||||
aaChartType = AAChartType.Column
|
aaChartType = AAChartType.Column
|
||||||
categories = chartPackets[0].names.map { it.toString() }
|
categories = chartPackets[0].names.map { it.toString() }
|
||||||
}
|
}
|
||||||
|
if (normalize && chartPackets.size > 1) {
|
||||||
|
chartPackets.forEach {
|
||||||
|
it.statData = normalizeData(it.statData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val namesMax = chartPackets.maxOf { it.names.size }
|
val namesMax = chartPackets.maxOf { it.names.size }
|
||||||
val palette = ColorEditor.generateColorPalette(primaryColor, namesMax)
|
val palette = ColorEditor.generateColorPalette(primaryColor, namesMax)
|
||||||
|
@ -76,20 +81,25 @@ class ChartBuilder {
|
||||||
ChartType.OneDimensional -> {
|
ChartType.OneDimensional -> {
|
||||||
val chart = AAChartModel()
|
val chart = AAChartModel()
|
||||||
.chartType(aaChartType)
|
.chartType(aaChartType)
|
||||||
.subtitle(getTypeName(statType, mediaType))
|
.subtitle(
|
||||||
|
getTypeName(
|
||||||
|
statType,
|
||||||
|
mediaType
|
||||||
|
) + if (normalize && chartPackets.size > 1) " (Normalized)" else ""
|
||||||
|
)
|
||||||
.zoomType(AAChartZoomType.None)
|
.zoomType(AAChartZoomType.None)
|
||||||
.dataLabelsEnabled(true)
|
.dataLabelsEnabled(true)
|
||||||
val elements: MutableList<Any> = mutableListOf()
|
val elements: MutableList<Any> = mutableListOf()
|
||||||
chartPackets.forEachIndexed { index, chartPacket ->
|
chartPackets.forEachIndexed { index, chartPacket ->
|
||||||
val element = AASeriesElement()
|
val element = AASeriesElement()
|
||||||
.name(chartPacket.username)
|
.name(chartPacket.username)
|
||||||
.data(
|
.data(
|
||||||
get1DElements(
|
get1DElements(
|
||||||
chartPacket.names,
|
chartPacket.names,
|
||||||
chartPacket.statData,
|
chartPacket.statData,
|
||||||
palette
|
palette
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
element.color(primaryColor)
|
element.color(primaryColor)
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,31 +119,66 @@ class ChartBuilder {
|
||||||
palette.map { String.format("#%06X", 0xFFFFFF and it) }.toTypedArray()
|
palette.map { String.format("#%06X", 0xFFFFFF and it) }.toTypedArray()
|
||||||
val chart = AAChartModel()
|
val chart = AAChartModel()
|
||||||
.chartType(aaChartType)
|
.chartType(aaChartType)
|
||||||
.subtitle(getTypeName(statType, mediaType))
|
.subtitle(
|
||||||
|
getTypeName(
|
||||||
|
statType,
|
||||||
|
mediaType
|
||||||
|
) + if (normalize && chartPackets.size > 1) " (Normalized)" else ""
|
||||||
|
)
|
||||||
.zoomType(AAChartZoomType.None)
|
.zoomType(AAChartZoomType.None)
|
||||||
.dataLabelsEnabled(false)
|
.dataLabelsEnabled(false)
|
||||||
.yAxisTitle(getTypeName(statType, mediaType))
|
.yAxisTitle(
|
||||||
if (chartPackets.size == 1) {
|
getTypeName(
|
||||||
chart.colorsTheme(hexColorsArray)
|
statType,
|
||||||
}
|
mediaType
|
||||||
|
) + if (normalize && chartPackets.size > 1) " (Normalized)" else ""
|
||||||
|
)
|
||||||
|
if (chartPackets.size == 1) {
|
||||||
|
chart.colorsTheme(hexColorsArray)
|
||||||
|
}
|
||||||
|
|
||||||
val elements: MutableList<AASeriesElement> = mutableListOf()
|
val elements: MutableList<AASeriesElement> = mutableListOf()
|
||||||
chartPackets.forEachIndexed { index, chartPacket ->
|
chartPackets.forEachIndexed { index, chartPacket ->
|
||||||
val element = get2DElements(
|
val element = get2DElements(
|
||||||
chartPacket.names,
|
chartPacket.names,
|
||||||
chartPacket.statData,
|
chartPacket.statData,
|
||||||
chartPackets.size == 1
|
chartPackets.size == 1
|
||||||
)
|
)
|
||||||
element.name(chartPacket.username)
|
element.name(chartPacket.username)
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
element.color(AAColor.rgbaColor(Color.red(primaryColor), Color.green(primaryColor), Color.blue(primaryColor), 0.9f))
|
element.color(
|
||||||
|
AAColor.rgbaColor(
|
||||||
|
Color.red(primaryColor),
|
||||||
|
Color.green(primaryColor),
|
||||||
|
Color.blue(primaryColor),
|
||||||
|
0.9f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
element.color(AAColor.rgbaColor(Color.red(ColorEditor.oppositeColor(primaryColor)), Color.green(ColorEditor.oppositeColor(primaryColor)), Color.blue(ColorEditor.oppositeColor(primaryColor)), 0.9f))
|
element.color(
|
||||||
|
AAColor.rgbaColor(
|
||||||
|
Color.red(
|
||||||
|
ColorEditor.oppositeColor(
|
||||||
|
primaryColor
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Color.green(ColorEditor.oppositeColor(primaryColor)),
|
||||||
|
Color.blue(ColorEditor.oppositeColor(primaryColor)),
|
||||||
|
0.9f
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (chartPackets.size == 1) {
|
if (chartPackets.size == 1) {
|
||||||
element.fillColor(AAColor.rgbaColor(Color.red(primaryColor), Color.green(primaryColor), Color.blue(primaryColor), 0.9f))
|
element.fillColor(
|
||||||
|
AAColor.rgbaColor(
|
||||||
|
Color.red(primaryColor),
|
||||||
|
Color.green(primaryColor),
|
||||||
|
Color.blue(primaryColor),
|
||||||
|
0.9f
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
elements.add(element)
|
elements.add(element)
|
||||||
}
|
}
|
||||||
|
@ -205,12 +250,12 @@ class ChartBuilder {
|
||||||
statValues.add(arrayOf(names[i], statData[i], statData[i]))
|
statValues.add(arrayOf(names[i], statData[i], statData[i]))
|
||||||
}
|
}
|
||||||
return AASeriesElement()
|
return AASeriesElement()
|
||||||
.data(statValues.toTypedArray())
|
.data(statValues.toTypedArray())
|
||||||
.dataLabels(
|
.dataLabels(
|
||||||
AADataLabels()
|
AADataLabels()
|
||||||
.enabled(false)
|
.enabled(false)
|
||||||
)
|
)
|
||||||
.colorByPoint(colorByPoint)
|
.colorByPoint(colorByPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun get1DElements(
|
private fun get1DElements(
|
||||||
|
@ -255,6 +300,14 @@ class ChartBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun normalizeData(data: List<Number>): List<Number> {
|
||||||
|
if (data.isEmpty()) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
val max = data.maxOf { it.toDouble() }
|
||||||
|
return data.map { (it.toDouble() / max) * 100 }
|
||||||
|
}
|
||||||
|
|
||||||
private fun setColors(aaOptions: AAOptions, context: Context, primaryColor: Int) {
|
private fun setColors(aaOptions: AAOptions, context: Context, primaryColor: Int) {
|
||||||
val backgroundColor = TypedValue()
|
val backgroundColor = TypedValue()
|
||||||
context.theme.resolveAttribute(
|
context.theme.resolveAttribute(
|
||||||
|
@ -281,7 +334,7 @@ class ChartBuilder {
|
||||||
Color.red(colorOnBackground.data),
|
Color.red(colorOnBackground.data),
|
||||||
Color.green(colorOnBackground.data),
|
Color.green(colorOnBackground.data),
|
||||||
Color.blue(colorOnBackground.data),
|
Color.blue(colorOnBackground.data),
|
||||||
0.9f
|
1.0f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -292,7 +345,7 @@ class ChartBuilder {
|
||||||
Color.red(backgroundColor.data),
|
Color.red(backgroundColor.data),
|
||||||
Color.green(backgroundColor.data),
|
Color.green(backgroundColor.data),
|
||||||
Color.blue(backgroundColor.data),
|
Color.blue(backgroundColor.data),
|
||||||
0.9f
|
1.0f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
aaOptions.title?.style(onBackgroundStyle)
|
aaOptions.title?.style(onBackgroundStyle)
|
||||||
|
|
|
@ -12,10 +12,10 @@ import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.anilist.Anilist
|
import ani.dantotsu.connections.anilist.Anilist
|
||||||
import ani.dantotsu.connections.anilist.api.Query
|
import ani.dantotsu.connections.anilist.api.Query
|
||||||
import ani.dantotsu.databinding.FragmentStatisticsBinding
|
import ani.dantotsu.databinding.FragmentStatisticsBinding
|
||||||
import ani.dantotsu.profile.ChartBuilder.Companion.ChartType
|
|
||||||
import ani.dantotsu.profile.ChartBuilder.Companion.StatType
|
|
||||||
import ani.dantotsu.profile.ChartBuilder.Companion.MediaType
|
|
||||||
import ani.dantotsu.profile.ChartBuilder.Companion.ChartPacket
|
import ani.dantotsu.profile.ChartBuilder.Companion.ChartPacket
|
||||||
|
import ani.dantotsu.profile.ChartBuilder.Companion.ChartType
|
||||||
|
import ani.dantotsu.profile.ChartBuilder.Companion.MediaType
|
||||||
|
import ani.dantotsu.profile.ChartBuilder.Companion.StatType
|
||||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartType
|
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartType
|
||||||
import com.xwray.groupie.GroupieAdapter
|
import com.xwray.groupie.GroupieAdapter
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -147,7 +147,7 @@ class StatsFragment :
|
||||||
|
|
||||||
private fun loadFormatChart(anime: Boolean) {
|
private fun loadFormatChart(anime: Boolean) {
|
||||||
val chartPackets = mutableListOf<ChartPacket>()
|
val chartPackets = mutableListOf<ChartPacket>()
|
||||||
stats.forEach {stat ->
|
stats.forEach { stat ->
|
||||||
val names: List<String> = if (anime) {
|
val names: List<String> = if (anime) {
|
||||||
stat?.statistics?.anime?.formats?.map { it.format } ?: emptyList()
|
stat?.statistics?.anime?.formats?.map { it.format } ?: emptyList()
|
||||||
} else {
|
} else {
|
||||||
|
@ -167,7 +167,7 @@ class StatsFragment :
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
if (names.isNotEmpty() && values.isNotEmpty()) {
|
if (names.isNotEmpty() && values.isNotEmpty()) {
|
||||||
chartPackets.add(ChartPacket(stat?.name?:"Unknown", names, values))
|
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chartPackets.isNotEmpty()) {
|
if (chartPackets.isNotEmpty()) {
|
||||||
|
@ -178,6 +178,7 @@ class StatsFragment :
|
||||||
statType,
|
statType,
|
||||||
type,
|
type,
|
||||||
chartPackets,
|
chartPackets,
|
||||||
|
xAxisName = "Format",
|
||||||
)
|
)
|
||||||
adapter.add(ChartItem("Format", formatChart, activity))
|
adapter.add(ChartItem("Format", formatChart, activity))
|
||||||
}
|
}
|
||||||
|
@ -215,7 +216,8 @@ class StatsFragment :
|
||||||
AAChartType.Funnel,
|
AAChartType.Funnel,
|
||||||
statType,
|
statType,
|
||||||
type,
|
type,
|
||||||
chartPackets
|
chartPackets,
|
||||||
|
xAxisName = "Status",
|
||||||
)
|
)
|
||||||
adapter.add(ChartItem("Status", statusChart, activity))
|
adapter.add(ChartItem("Status", statusChart, activity))
|
||||||
}
|
}
|
||||||
|
@ -225,9 +227,19 @@ class StatsFragment :
|
||||||
val chartPackets = mutableListOf<ChartPacket>()
|
val chartPackets = mutableListOf<ChartPacket>()
|
||||||
stats.forEach { stat ->
|
stats.forEach { stat ->
|
||||||
val names: List<Int> = if (anime) {
|
val names: List<Int> = if (anime) {
|
||||||
stat?.statistics?.anime?.scores?.map { convertScore(it.score, stat.mediaListOptions.scoreFormat) } ?: emptyList()
|
stat?.statistics?.anime?.scores?.map {
|
||||||
|
convertScore(
|
||||||
|
it.score,
|
||||||
|
stat.mediaListOptions.scoreFormat
|
||||||
|
)
|
||||||
|
} ?: emptyList()
|
||||||
} else {
|
} else {
|
||||||
stat?.statistics?.manga?.scores?.map { convertScore(it.score, stat.mediaListOptions.scoreFormat) } ?: emptyList()
|
stat?.statistics?.manga?.scores?.map {
|
||||||
|
convertScore(
|
||||||
|
it.score,
|
||||||
|
stat.mediaListOptions.scoreFormat
|
||||||
|
)
|
||||||
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
val values: List<Number> = if (anime) {
|
val values: List<Number> = if (anime) {
|
||||||
when (statType) {
|
when (statType) {
|
||||||
|
@ -337,6 +349,7 @@ class StatsFragment :
|
||||||
type,
|
type,
|
||||||
chartPackets,
|
chartPackets,
|
||||||
xAxisName = "Year",
|
xAxisName = "Year",
|
||||||
|
scrollPos = 0.0f
|
||||||
)
|
)
|
||||||
adapter.add(ChartItem("Release Year", releaseYearChart, activity))
|
adapter.add(ChartItem("Release Year", releaseYearChart, activity))
|
||||||
}
|
}
|
||||||
|
@ -429,6 +442,7 @@ class StatsFragment :
|
||||||
xAxisName = "Genre",
|
xAxisName = "Genre",
|
||||||
polar = true,
|
polar = true,
|
||||||
passedCategories = chartPackets[0].names as List<String>,
|
passedCategories = chartPackets[0].names as List<String>,
|
||||||
|
normalize = true
|
||||||
)
|
)
|
||||||
adapter.add(ChartItem("Genre", genreChart, activity))
|
adapter.add(ChartItem("Genre", genreChart, activity))
|
||||||
}
|
}
|
||||||
|
@ -546,9 +560,11 @@ class StatsFragment :
|
||||||
val chartPackets = mutableListOf<ChartPacket>()
|
val chartPackets = mutableListOf<ChartPacket>()
|
||||||
stats.forEach { stat ->
|
stats.forEach { stat ->
|
||||||
val names: List<String> = if (anime) {
|
val names: List<String> = if (anime) {
|
||||||
stat?.statistics?.anime?.voiceActors?.map { it.voiceActor.name.full?:"unknown" } ?: emptyList()
|
stat?.statistics?.anime?.voiceActors?.map { it.voiceActor.name.full ?: "unknown" }
|
||||||
|
?: emptyList()
|
||||||
} else {
|
} else {
|
||||||
stat?.statistics?.manga?.voiceActors?.map { it.voiceActor.name.full?:"unknown" } ?: emptyList()
|
stat?.statistics?.manga?.voiceActors?.map { it.voiceActor.name.full ?: "unknown" }
|
||||||
|
?: emptyList()
|
||||||
}
|
}
|
||||||
val values: List<Number> = if (anime) {
|
val values: List<Number> = if (anime) {
|
||||||
when (statType) {
|
when (statType) {
|
||||||
|
@ -644,7 +660,8 @@ class StatsFragment :
|
||||||
xAxisName = "Studio",
|
xAxisName = "Studio",
|
||||||
polar = true,
|
polar = true,
|
||||||
passedCategories = chartPackets[0].names as List<String>,
|
passedCategories = chartPackets[0].names as List<String>,
|
||||||
scrollPos = null
|
scrollPos = null,
|
||||||
|
normalize = true
|
||||||
)
|
)
|
||||||
adapter.add(ChartItem("Studio", studioChart, activity))
|
adapter.add(ChartItem("Studio", studioChart, activity))
|
||||||
}
|
}
|
||||||
|
@ -654,9 +671,11 @@ class StatsFragment :
|
||||||
val chartPackets = mutableListOf<ChartPacket>()
|
val chartPackets = mutableListOf<ChartPacket>()
|
||||||
stats.forEach { stat ->
|
stats.forEach { stat ->
|
||||||
val names: List<String> = if (anime) {
|
val names: List<String> = if (anime) {
|
||||||
stat?.statistics?.anime?.staff?.map { it.staff.name.full?:"unknown" } ?: emptyList()
|
stat?.statistics?.anime?.staff?.map { it.staff.name.full ?: "unknown" }
|
||||||
|
?: emptyList()
|
||||||
} else {
|
} else {
|
||||||
stat?.statistics?.manga?.staff?.map { it.staff.name.full?:"unknown" } ?: emptyList()
|
stat?.statistics?.manga?.staff?.map { it.staff.name.full ?: "unknown" }
|
||||||
|
?: emptyList()
|
||||||
}
|
}
|
||||||
val values: List<Number> = if (anime) {
|
val values: List<Number> = if (anime) {
|
||||||
when (statType) {
|
when (statType) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue