mirror of
https://github.com/ankitects/anki.git
synced 2026-01-10 12:33:55 -05:00
Fix: Add minimum bin width
This commit is contained in:
parent
372d15578f
commit
932f8cc5eb
3 changed files with 35 additions and 55 deletions
|
|
@ -8,13 +8,13 @@
|
||||||
import type { GraphsResponse } from "@generated/anki/stats_pb";
|
import type { GraphsResponse } from "@generated/anki/stats_pb";
|
||||||
import * as tr from "@generated/ftl";
|
import * as tr from "@generated/ftl";
|
||||||
import { localizedNumber } from "@tslib/i18n";
|
import { localizedNumber } from "@tslib/i18n";
|
||||||
import type { Bin, ScaleLinear } from "d3";
|
import type { Bin } from "d3";
|
||||||
import { bin, interpolateRdYlGn, scaleLinear, scaleSequential, sum } from "d3";
|
import { bin, interpolateRdYlGn, scaleSequential, sum } from "d3";
|
||||||
|
|
||||||
import type { SearchDispatch, TableDatum } from "./graph-helpers";
|
import type { SearchDispatch, TableDatum } from "./graph-helpers";
|
||||||
import { getNumericMapBinValue, numericMap } from "./graph-helpers";
|
import { getNumericMapBinValue, numericMap } from "./graph-helpers";
|
||||||
import type { HistogramData } from "./histogram-graph";
|
import type { HistogramData } from "./histogram-graph";
|
||||||
import { percentageRangeMinMax } from "./percentageRange";
|
import { getAdjustedScaleAndTicks, percentageRangeMinMax } from "./percentageRange";
|
||||||
|
|
||||||
export interface GraphData {
|
export interface GraphData {
|
||||||
eases: Map<number, number>;
|
eases: Map<number, number>;
|
||||||
|
|
@ -34,30 +34,6 @@ function makeQuery(start: number, end: number): string {
|
||||||
return `${fromQuery} AND ${tillQuery}`;
|
return `${fromQuery} AND ${tillQuery}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAdjustedScaleAndTicks(
|
|
||||||
min: number,
|
|
||||||
max: number,
|
|
||||||
desiredBars: number,
|
|
||||||
): [ScaleLinear<number, number, never>, number[]] {
|
|
||||||
const prescale = scaleLinear().domain([min, max]).nice();
|
|
||||||
const ticks = prescale.ticks(desiredBars);
|
|
||||||
|
|
||||||
const predomain = prescale.domain() as [number, number];
|
|
||||||
|
|
||||||
const minOffset = min - predomain[0];
|
|
||||||
const tickSize = ticks[1] - ticks[0];
|
|
||||||
|
|
||||||
if (minOffset === 0 || (minOffset % tickSize !== 0 && tickSize % minOffset !== 0)) {
|
|
||||||
return [prescale, ticks];
|
|
||||||
}
|
|
||||||
|
|
||||||
const add = (n: number): number => n + minOffset;
|
|
||||||
return [
|
|
||||||
scaleLinear().domain(predomain.map(add) as [number, number]),
|
|
||||||
ticks.map(add),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function prepareData(
|
export function prepareData(
|
||||||
data: GraphData,
|
data: GraphData,
|
||||||
dispatch: SearchDispatch,
|
dispatch: SearchDispatch,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
|
||||||
import { sum } from "d3";
|
import { range, type ScaleLinear, scaleLinear, sum } from "d3";
|
||||||
|
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
export enum PercentageRangeEnum {
|
export enum PercentageRangeEnum {
|
||||||
|
|
@ -33,3 +33,31 @@ export function percentageRangeMinMax(data: Map<number, number>, range: number |
|
||||||
|
|
||||||
return [xMin, xMax];
|
return [xMin, xMax];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAdjustedScaleAndTicks(
|
||||||
|
min: number,
|
||||||
|
max: number,
|
||||||
|
desiredBars: number,
|
||||||
|
): [ScaleLinear<number, number, never>, number[]] {
|
||||||
|
const prescale = scaleLinear().domain([min, max]).nice();
|
||||||
|
let ticks = prescale.ticks(desiredBars);
|
||||||
|
|
||||||
|
const predomain = prescale.domain() as [number, number];
|
||||||
|
|
||||||
|
const minOffset = min - predomain[0];
|
||||||
|
const tickSize = ticks[1] - ticks[0];
|
||||||
|
|
||||||
|
if (tickSize < 1) {
|
||||||
|
ticks = range(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minOffset === 0 || (minOffset % tickSize !== 0 && tickSize % minOffset !== 0)) {
|
||||||
|
return [prescale, ticks];
|
||||||
|
}
|
||||||
|
|
||||||
|
const add = (n: number): number => n + minOffset;
|
||||||
|
return [
|
||||||
|
scaleLinear().domain(predomain.map(add) as [number, number]),
|
||||||
|
ticks.map(add),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@
|
||||||
import type { GraphsResponse } from "@generated/anki/stats_pb";
|
import type { GraphsResponse } from "@generated/anki/stats_pb";
|
||||||
import * as tr from "@generated/ftl";
|
import * as tr from "@generated/ftl";
|
||||||
import { localizedNumber } from "@tslib/i18n";
|
import { localizedNumber } from "@tslib/i18n";
|
||||||
import type { Bin, ScaleLinear } from "d3";
|
import type { Bin } from "d3";
|
||||||
import { bin, interpolateRdYlGn, scaleLinear, scaleSequential, sum } from "d3";
|
import { bin, interpolateRdYlGn, scaleSequential, sum } from "d3";
|
||||||
|
|
||||||
import type { SearchDispatch, TableDatum } from "./graph-helpers";
|
import type { SearchDispatch, TableDatum } from "./graph-helpers";
|
||||||
import { getNumericMapBinValue, numericMap } from "./graph-helpers";
|
import { getNumericMapBinValue, numericMap } from "./graph-helpers";
|
||||||
import type { HistogramData } from "./histogram-graph";
|
import type { HistogramData } from "./histogram-graph";
|
||||||
import { percentageRangeMinMax } from "./percentageRange";
|
import { getAdjustedScaleAndTicks, percentageRangeMinMax } from "./percentageRange";
|
||||||
|
|
||||||
export interface GraphData {
|
export interface GraphData {
|
||||||
retrievability: Map<number, number>;
|
retrievability: Map<number, number>;
|
||||||
|
|
@ -41,30 +41,6 @@ function makeQuery(start: number, end: number): string {
|
||||||
return `${fromQuery} AND ${tillQuery}`;
|
return `${fromQuery} AND ${tillQuery}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAdjustedScaleAndTicks(
|
|
||||||
min: number,
|
|
||||||
max: number,
|
|
||||||
desiredBars: number,
|
|
||||||
): [ScaleLinear<number, number, never>, number[]] {
|
|
||||||
const prescale = scaleLinear().domain([min, max]).nice();
|
|
||||||
const ticks = prescale.ticks(desiredBars);
|
|
||||||
|
|
||||||
const predomain = prescale.domain() as [number, number];
|
|
||||||
|
|
||||||
const minOffset = min - predomain[0];
|
|
||||||
const tickSize = ticks[1] - ticks[0];
|
|
||||||
|
|
||||||
if (minOffset === 0 || (minOffset % tickSize !== 0 && tickSize % minOffset !== 0)) {
|
|
||||||
return [prescale, ticks];
|
|
||||||
}
|
|
||||||
|
|
||||||
const add = (n: number): number => n + minOffset;
|
|
||||||
return [
|
|
||||||
scaleLinear().domain(predomain.map(add) as [number, number]),
|
|
||||||
ticks.map(add),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function prepareData(
|
export function prepareData(
|
||||||
data: GraphData,
|
data: GraphData,
|
||||||
dispatch: SearchDispatch,
|
dispatch: SearchDispatch,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue