///|
fn scalar_prepare_locations(
base : BaseFormatter,
) -> Array[ScalarNumber] raise @core.DataError {
let locations = scalar_numpy_locations(base.locations)
Array::makei(locations.length(), index => {
scalar_numeric_location(locations, index)
})
}
///|
fn scalar_prepare_visible(
locations : FormatterLocations,
lower : ScalarNumber,
upper : ScalarNumber,
) -> Array[ScalarNumber] raise @core.DataError {
let locations = scalar_numpy_locations(locations)
let result = []
for index in 0.. (ScalarNumber, ScalarNumber) raise @core.DataError {
let mut lower = values[0]
let mut upper = values[0]
for index in 1.. v.is_nan()
_ => false
}) {
lower = value
}
if scalar_numeric_less(upper, value) ||
(match value {
Number(v) | NumpyFloat64(v) => v.is_nan()
_ => false
}) {
upper = value
}
}
}
(lower, upper)
}
///|
fn scalar_prepare_offset(
base : BaseFormatter,
state : ScalarFormatterState,
) -> Unit raise @core.DataError {
let zero = ScalarNumber::Integer(@bigint.BigInt::from_int(0))
let locations = base.locations
let (vmin, vmax) = scalar_numeric_view(base, sort=true)
let values = scalar_prepare_visible(locations, vmin, vmax)
if values.is_empty() {
state.offset = Some(zero)
return
}
let (lmin, lmax) = scalar_prepare_extrema(values)
if scalar_numeric_equal(lmin, lmax) ||
(!scalar_numeric_less(zero, lmin) && !scalar_numeric_less(lmax, zero)) {
state.offset = Some(zero)
return
}
let first = scalar_numeric_double(lmin)
let last = scalar_numeric_double(lmax)
let a = Double::abs(first)
let b = Double::abs(last)
let abs_min = if b < a { b } else { a }
let abs_max = if b < a { a } else { b }
if abs_min == abs_max && !scalar_numeric_equal(lmin, lmax) {
raise @core.DataError::InvalidTicks(
message="Unsupported: unequal integer extrema collapse to one float; upstream offset search does not terminate",
)
}
let sign = if first.reinterpret_as_uint64() >> 63 != 0UL { -1.0 } else { 1.0 }
let maximum = scalar_math_log10(ScalarNumber::Number(abs_max)).ceil()
let mut phase = maximum
while true {
let power = scalar_math_pow10(phase)
if scalar_numeric_float_floor_divide(abs_min, power) !=
scalar_numeric_float_floor_divide(abs_max, power) {
break
}
phase -= 1.0
}
let mut oom = 1.0 + phase
if (abs_max - abs_min) / scalar_math_pow10(oom) <= 1.0e-2 {
phase = maximum
while true {
let power = scalar_math_pow10(phase)
if scalar_numeric_float_floor_divide(abs_max, power) -
scalar_numeric_float_floor_divide(abs_min, power) >
1.0 {
break
}
phase -= 1.0
}
oom = 1.0 + phase
}
let power = scalar_math_pow10(oom)
let prefix = scalar_numeric_float_floor_divide(abs_max, power)
let threshold = scalar_math_power10(
ScalarNumber::Integer(state.offset_threshold - @bigint.BigInt::from_int(1)),
float_base=false,
)
if !scalar_numeric_less(ScalarNumber::NumpyFloat64(prefix), threshold) &&
!prefix.is_nan() {
let signed = sign * prefix
state.offset = Some(ScalarNumber::NumpyFloat64(signed * power))
} else {
state.offset = Some(zero)
}
}
///|
fn scalar_prepare_order(
base : BaseFormatter,
state : ScalarFormatterState,
) -> Unit raise @core.DataError {
let zero = ScalarNumber::Integer(@bigint.BigInt::from_int(0))
if !state.scientific {
state.order = zero
return
}
let first = scalar_power_limit_at(state.power_limits, 0)
let second = scalar_power_limit_at(state.power_limits, 1)
if scalar_numeric_equal(first, second) && scalar_numeric_truth(Some(second)) {
state.order = scalar_power_limit_at(state.power_limits, 0)
return
}
let (vmin, vmax) = scalar_numeric_view(base, sort=true)
let values = scalar_prepare_visible(base.locations, vmin, vmax).map(
scalar_numeric_abs,
)
if values.is_empty() {
state.order = zero
return
}
let oom = if scalar_numeric_truth(state.offset) {
scalar_numeric_floor(scalar_math_log10(scalar_numeric_op(vmax, vmin, 1)))
} else {
let value = scalar_prepare_extrema(values).1
if scalar_numeric_equal(value, zero) {
@bigint.BigInt::from_int(0)
} else {
scalar_numeric_floor(scalar_math_log10(value))
}
}
let order = ScalarNumber::Integer(oom)
let low = scalar_numeric_compare(
order,
scalar_power_limit_at(state.power_limits, 0),
)
if low == Some(-1) || low == Some(0) {
state.order = order
} else {
let high = scalar_numeric_compare(
order,
scalar_power_limit_at(state.power_limits, 1),
)
state.order = if high == Some(1) || high == Some(0) { order } else { zero }
}
}
///|
// np.asarray of the temporary Python list chooses object only outside both
// fixed-width integer domains. Signed/unsigned mixing promotes to float64.
fn scalar_prepare_promote(
values : Array[ScalarNumber],
) -> (Array[ScalarNumber], Bool) raise @core.DataError {
let mut floating = false
let mut unsigned = false
let mut object = false
for value in values {
match value {
Number(_) | NumpyFloat64(_) => floating = true
Integer(integer) =>
if integer < @bigint.BigInt::from_int64(-9223372036854775808L) ||
integer > @bigint.BigInt::from_uint64(18446744073709551615UL) {
object = true
} else if integer > @bigint.BigInt::from_int64(9223372036854775807L) {
unsigned = true
}
_ => ()
}
}
if object {
return (values, true)
}
if floating || unsigned {
(
values.map(value => {
ScalarNumber::NumpyFloat64(scalar_numeric_double(value))
}),
false,
)
} else {
(
values.map(value => ScalarNumber::NumpyInt64(scalar_numeric_int64(value))),
false,
)
}
}
///|
fn scalar_prepare_format(
base : BaseFormatter,
state : ScalarFormatterState,
) -> Unit raise @core.DataError {
let short = base.locations.length() < 2
let mut locations = if short {
match base.locations {
Sequence(values) => values.map(value => ScalarNumber::Number(value))
Integers(values) => values.map(value => ScalarNumber::Integer(value))
NdArray(_) | Typed(_) => scalar_prepare_locations(base)
}
} else {
scalar_prepare_locations(base)
}
let mut object = false
if short {
let view = match base.axis {
Some(axis) => axis.view_interval()
None =>
raise @core.DataError::InvalidTicks(
message="AttributeError: 'NoneType' object has no attribute 'get_view_interval'",
)
}
for index in 0.. ScalarNumber::Number(values[index])
Integers(values) => ScalarNumber::Integer(values[index])
NdArray(values) =>
if values.is_int64() {
ScalarNumber::NumpyInt64(values.get_int64(index))
} else {
ScalarNumber::NumpyFloat64(values.get(index))
}
},
)
}
let (promoted, is_object) = scalar_prepare_promote(locations)
locations = promoted
object = is_object
}
let subtracted = locations.map(value => {
scalar_numeric_sub_offset(value, state.offset)
})
let power = scalar_math_power10(state.order, float_base=true)
locations = subtracted.map(value => scalar_numeric_op(value, power, 3))
let (lower, upper) = scalar_prepare_extrema(locations, object~)
let mut range = scalar_numeric_op(upper, lower, 1)
let zero = ScalarNumber::Integer(@bigint.BigInt::from_int(0))
if scalar_numeric_equal(range, zero) {
range = scalar_prepare_extrema(locations.map(scalar_numeric_abs), object~).1
}
if scalar_numeric_equal(range, zero) {
range = ScalarNumber::Integer(@bigint.BigInt::from_int(1))
}
if base.locations.length() < 2 {
let length = Int32::max(0, locations.length() - 2)
locations = Array::makei(length, index => locations[index])
}
let oom = scalar_numeric_floor(scalar_math_log10(range))
let mut precision = Int32::max(0, 3 - oom.to_int())
let threshold = scalar_numeric_double(
scalar_numeric_op(
ScalarNumber::Number(1.0e-3),
scalar_math_power10(ScalarNumber::Integer(oom), float_base=false),
2,
),
)
while precision >= 0 {
if locations.is_empty() {
raise @core.DataError::InvalidTicks(
message="ValueError: zero-size array to reduction operation maximum which has no identity",
)
}
if object {
let name = if scalar_numeric_numpy(locations[0]) {
"numpy.float64"
} else {
"float"
}
raise @core.DataError::InvalidTicks(
message="TypeError: loop of ufunc does not support argument 0 of type " +
name +
" which has no callable rint method",
)
}
let errors = locations.map(value => {
let value = scalar_numeric_double(value)
Double::abs(value - scalar_math_numpy_round(value, precision))
})
let mut maximum = errors[0]
for index in 1.. maximum {
maximum = errors[index]
}
}
if maximum < threshold {
precision -= 1
} else {
break
}
}
precision += 1
let pattern = "%1." + precision.to_string() + "f"
state.format_pattern = if state.usetex || state.use_math_text {
"$\\mathdefault{" + pattern + "}$"
} else {
pattern
}
}
///|
fn scalar_named_prepare(
base : BaseFormatter,
state : ScalarFormatterState,
) -> Unit raise @core.DataError {
if base.locations.length() > 0 {
if state.use_offset {
scalar_prepare_offset(base, state)
}
scalar_prepare_order(base, state)
scalar_prepare_format(base, state)
}
}
///|
fn scalar_numpy_locations(
locations : FormatterLocations,
) -> FormatterLocations raise @core.DataError {
match locations {
Integers(values) =>
LogitInput::from_keys(
values.map(value => LogitKey::new(ScalarNumber::Integer(value))),
).snapshot()
_ => locations
}
}