parent
bc1c653bc2
commit
e05d0671e6
@ -0,0 +1,84 @@ |
|||||||
|
package net.pokeranalytics.android.calcul |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import com.github.mikephil.charting.data.* |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.calculus.ComputedResults |
||||||
|
import net.pokeranalytics.android.calculus.Point |
||||||
|
import net.pokeranalytics.android.calculus.Stat |
||||||
|
import net.pokeranalytics.android.ui.graph.DataSetFactory |
||||||
|
import kotlin.math.abs |
||||||
|
|
||||||
|
|
||||||
|
// MPAndroidChart |
||||||
|
|
||||||
|
fun ComputedResults.defaultStatEntries(stat: Stat, context: Context): DataSet<out Entry> { |
||||||
|
return when (stat) { |
||||||
|
Stat.NUMBER_OF_SETS, Stat.NUMBER_OF_GAMES, Stat.HOURLY_DURATION -> this.barEntries(stat, context = context) |
||||||
|
Stat.STANDARD_DEVIATION -> this.distributionEntries(stat, context) |
||||||
|
else -> this.singleLineEntries(stat, context) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun ComputedResults.singleLineEntries(stat: Stat, context: Context): LineDataSet { |
||||||
|
val entries = mutableListOf<Entry>() |
||||||
|
this.evolutionValues[stat]?.let { points -> |
||||||
|
points.forEachIndexed { index, p -> |
||||||
|
entries.add(Entry(index.toFloat(), p.y.toFloat(), p.data)) |
||||||
|
} |
||||||
|
} |
||||||
|
return DataSetFactory.lineDataSetInstance(entries, this.group.query.getName(context), context) |
||||||
|
} |
||||||
|
|
||||||
|
fun ComputedResults.durationEntries(stat: Stat, context: Context): LineDataSet { |
||||||
|
val entries = mutableListOf<Entry>() |
||||||
|
this.evolutionValues[stat]?.let { points -> |
||||||
|
points.forEach { p -> |
||||||
|
entries.add(Entry(p.x.toFloat(), p.y.toFloat(), p.data)) |
||||||
|
} |
||||||
|
} |
||||||
|
return DataSetFactory.lineDataSetInstance(entries, stat.name, context) |
||||||
|
} |
||||||
|
|
||||||
|
private fun ComputedResults.barEntries(stat: Stat, context: Context): BarDataSet { |
||||||
|
|
||||||
|
val entries = mutableListOf<BarEntry>() |
||||||
|
this.evolutionValues[stat]?.let { points -> |
||||||
|
points.forEach { p -> |
||||||
|
entries.add(BarEntry(p.x.toFloat(), p.y.toFloat(), p.data)) |
||||||
|
} |
||||||
|
} |
||||||
|
return DataSetFactory.barDataSetInstance(entries, stat.name, context) |
||||||
|
} |
||||||
|
|
||||||
|
private fun ComputedResults.distributionEntries(stat: Stat, context: Context): BarDataSet { |
||||||
|
|
||||||
|
val colors = mutableListOf<Int>() |
||||||
|
val entries = mutableListOf<BarEntry>() |
||||||
|
this.evolutionValues[stat]?.let { points -> |
||||||
|
|
||||||
|
val negative = mutableListOf<Point>() |
||||||
|
val positive = mutableListOf<Point>() |
||||||
|
|
||||||
|
points.sortByDescending { it.y } |
||||||
|
points.forEach { |
||||||
|
if (it.y < 0) { |
||||||
|
negative.add(it) |
||||||
|
} else { |
||||||
|
positive.add(it) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
negative.forEachIndexed { index, p -> |
||||||
|
entries.add(BarEntry(index.toFloat(), abs(p.y.toFloat()), p.data)) |
||||||
|
colors.add(context.getColor(R.color.red)) |
||||||
|
} |
||||||
|
positive.forEachIndexed { index, p -> |
||||||
|
val x = negative.size + index.toFloat() |
||||||
|
entries.add(BarEntry(x, p.y.toFloat(), p.data)) |
||||||
|
colors.add(context.getColor(R.color.green)) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
return DataSetFactory.barDataSetInstance(entries, stat.name, context, colors) |
||||||
|
} |
||||||
@ -0,0 +1,64 @@ |
|||||||
|
package net.pokeranalytics.android.calcul |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import com.github.mikephil.charting.data.BarDataSet |
||||||
|
import com.github.mikephil.charting.data.BarEntry |
||||||
|
import com.github.mikephil.charting.data.Entry |
||||||
|
import com.github.mikephil.charting.data.LineDataSet |
||||||
|
import net.pokeranalytics.android.calculus.Report |
||||||
|
import net.pokeranalytics.android.calculus.Stat |
||||||
|
import net.pokeranalytics.android.ui.graph.DataSetFactory |
||||||
|
import net.pokeranalytics.android.util.ColorUtils |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the list of entries corresponding to the provided [stat] |
||||||
|
* One value will be returned by result |
||||||
|
*/ |
||||||
|
fun Report.lineEntries(stat: Stat? = null, context: Context): LineDataSet { |
||||||
|
val entries = mutableListOf<Entry>() |
||||||
|
val statToUse = stat ?: this.options.stats.firstOrNull() |
||||||
|
val statName = statToUse?.name ?: "" |
||||||
|
|
||||||
|
statToUse?.let { |
||||||
|
this.results.forEachIndexed { index, results -> |
||||||
|
results.computedStat(it)?.progressValue?.let { progressValue -> |
||||||
|
entries.add(Entry(index.toFloat(), progressValue.toFloat(), results)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return DataSetFactory.lineDataSetInstance(entries, statName, context) |
||||||
|
} |
||||||
|
|
||||||
|
fun Report.barEntries(stat: Stat? = null, context: Context): BarDataSet { |
||||||
|
val entries = mutableListOf<BarEntry>() |
||||||
|
val statToUse = stat ?: options.stats.firstOrNull() |
||||||
|
|
||||||
|
statToUse?.let { |
||||||
|
this.results.forEachIndexed { index, results -> |
||||||
|
val cs = results.computedStat(it) |
||||||
|
cs?.let { computedStat -> |
||||||
|
val barEntry = BarEntry(index.toFloat(), computedStat.value.toFloat(), results) |
||||||
|
entries.add(barEntry) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val label = statToUse?.name ?: "" |
||||||
|
return DataSetFactory.barDataSetInstance(entries, label, context) |
||||||
|
} |
||||||
|
|
||||||
|
fun Report.multiLineEntries(context: Context): List<LineDataSet> { |
||||||
|
val dataSets = mutableListOf<LineDataSet>() |
||||||
|
|
||||||
|
options.stats.forEach { stat -> |
||||||
|
this.results.forEachIndexed { index, result -> |
||||||
|
val ds = result.singleLineEntries(stat, context) |
||||||
|
ds.color = ColorUtils.almostRandomColor(index, context) |
||||||
|
dataSets.add(ds) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return dataSets |
||||||
|
} |
||||||
@ -0,0 +1,90 @@ |
|||||||
|
package net.pokeranalytics.android.calculus |
||||||
|
|
||||||
|
import io.realm.Realm |
||||||
|
import io.realm.RealmResults |
||||||
|
import net.pokeranalytics.android.model.filter.Query |
||||||
|
import net.pokeranalytics.android.model.filter.QueryCondition |
||||||
|
import net.pokeranalytics.android.model.realm.ComputableResult |
||||||
|
import net.pokeranalytics.android.model.realm.Filter |
||||||
|
import net.pokeranalytics.android.model.realm.SessionSet |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* A sessionGroup of computable items identified by a name |
||||||
|
*/ |
||||||
|
class ComputableGroup(var query: Query, var stats: List<Stat>? = null) { |
||||||
|
|
||||||
|
/** |
||||||
|
* A subgroup used to compute stat variation |
||||||
|
*/ |
||||||
|
var comparedGroup: ComputableGroup? = null |
||||||
|
|
||||||
|
/** |
||||||
|
* The computed statIds of the comparable sessionGroup |
||||||
|
*/ |
||||||
|
var comparedComputedResults: ComputedResults? = null |
||||||
|
|
||||||
|
/** |
||||||
|
* A list of _conditions to get |
||||||
|
*/ |
||||||
|
val conditions: List<QueryCondition> |
||||||
|
get() { |
||||||
|
return this.query.conditions |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The list of endedSessions to compute |
||||||
|
*/ |
||||||
|
private var _computables: RealmResults<ComputableResult>? = null |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the computables on the relative [realm] filtered with the provided [conditions] |
||||||
|
*/ |
||||||
|
fun computables(realm: Realm, sorted: Boolean = false): RealmResults<ComputableResult> { |
||||||
|
|
||||||
|
// if computables exists and is valid (previous realm not closed) |
||||||
|
this._computables?.let { |
||||||
|
if (it.isValid) { |
||||||
|
return it |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val sortedField = if (sorted) "session.startDate" else null |
||||||
|
val computables = Filter.queryOn<ComputableResult>(realm, this.query, sortedField) |
||||||
|
this._computables = computables |
||||||
|
return computables |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The list of sets to compute |
||||||
|
*/ |
||||||
|
private var _sessionSets: RealmResults<SessionSet>? = null |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the session sets on the relative [realm] filtered with the provided [conditions] |
||||||
|
*/ |
||||||
|
fun sessionSets(realm: Realm, sorted: Boolean = false): RealmResults<SessionSet> { |
||||||
|
// if computables exists and is valid (previous realm not closed) |
||||||
|
this._sessionSets?.let { |
||||||
|
if (it.isValid) { |
||||||
|
return it |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val sortedField = if (sorted) SessionSet.Field.START_DATE.identifier else null |
||||||
|
val sets = Filter.queryOn<SessionSet>(realm, this.query, sortedField) |
||||||
|
this._sessionSets = sets |
||||||
|
return sets |
||||||
|
} |
||||||
|
|
||||||
|
fun cleanup() { |
||||||
|
this._computables = null |
||||||
|
this._sessionSets = null |
||||||
|
} |
||||||
|
|
||||||
|
val isEmpty: Boolean |
||||||
|
get() { |
||||||
|
return this._computables?.isEmpty() ?: true |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue