///|
/// Mutable defaults shared by newly created figures and axes.
pub struct RcParams {
priv mut formatter_min_exponent : @bigint.BigInt
priv mut formatter_use_offset : Bool
priv mut formatter_use_math_text : Bool
priv mut formatter_use_locale : Bool
priv mut formatter_offset_threshold : @bigint.BigInt
priv mut formatter_limits : Array[@bigint.BigInt]
priv mut text_usetex : Bool
priv mut unicode_minus : Bool
priv mut x_minor_ticks_visible : Bool
priv mut y_minor_ticks_visible : Bool
priv mut x_minor_tick_divisions : MinorTickDivisions
priv mut y_minor_tick_divisions : MinorTickDivisions
priv mut classic_mode : Bool
priv mut axes_autolimit_mode : String
priv mut timezone : String
priv mut date_converter : String
priv mut date_interval_multiples : Bool
priv mut lines_scale_dashes : Bool
priv mut lines_dashed_pattern : Array[Double]
priv mut lines_dashdot_pattern : Array[Double]
priv mut lines_dotted_pattern : Array[Double]
priv date_autoformats : Array[String]
mut date_epoch : String
color_cycle : Array[String]
mut x_margin : Double
mut y_margin : Double
mut grid_visible : Bool
mut grid_color : String
mut grid_linewidth : Double
}
///|
fn tab10() -> Array[String] {
[
"#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2",
"#7f7f7f", "#bcbd22", "#17becf",
]
}
///|
fn default_rc_params() -> RcParams {
{
formatter_min_exponent: @bigint.BigInt::from_int(0),
formatter_use_offset: true,
formatter_use_math_text: false,
formatter_use_locale: false,
formatter_offset_threshold: @bigint.BigInt::from_int(4),
formatter_limits: [
@bigint.BigInt::from_int(-5),
@bigint.BigInt::from_int(6),
],
text_usetex: false,
unicode_minus: true,
x_minor_ticks_visible: false,
y_minor_ticks_visible: false,
x_minor_tick_divisions: Text("auto"),
y_minor_tick_divisions: Text("auto"),
classic_mode: false,
axes_autolimit_mode: "data",
timezone: "UTC",
date_converter: "auto",
date_interval_multiples: true,
lines_scale_dashes: true,
lines_dashed_pattern: [3.7, 1.6],
lines_dashdot_pattern: [6.4, 1.6, 1.0, 1.6],
lines_dotted_pattern: [1.0, 1.65],
date_autoformats: [
"%Y", "%Y-%m", "%Y-%m-%d", "%m-%d %H", "%d %H:%M", "%H:%M:%S", "%M:%S.%f",
],
date_epoch: "1970-01-01T00:00:00",
color_cycle: tab10(),
x_margin: 0.05,
y_margin: 0.05,
grid_visible: false,
grid_color: "#e5e7eb",
grid_linewidth: 1.0,
}
}
///|
let current : @ref.Ref[RcParams] = @ref.new(default_rc_params())
///|
fn validate_margin(value : Double) -> Unit raise @core.DataError {
if value.is_nan() || value.is_inf() || value <= -0.5 {
raise @core.DataError::InvalidTicks(
message="axes margins must be finite and greater than -0.5",
)
}
}
///|
fn validate_color_cycle(colors : Array[String]) -> Unit raise @core.DataError {
if colors.length() == 0 {
raise @core.DataError::InvalidTicks(
message="color cycle must contain at least one color",
)
}
for color in colors {
if color.length() == 0 {
raise @core.DataError::InvalidTicks(
message="color cycle entries must not be empty",
)
}
}
}
///|
/// Return a copy of the current defaults.
pub fn rc_params() -> RcParams {
let value = current.val
{
formatter_min_exponent: value.formatter_min_exponent,
formatter_use_offset: value.formatter_use_offset,
formatter_use_math_text: value.formatter_use_math_text,
formatter_use_locale: value.formatter_use_locale,
formatter_offset_threshold: value.formatter_offset_threshold,
formatter_limits: value.formatter_limits,
text_usetex: value.text_usetex,
unicode_minus: value.unicode_minus,
x_minor_ticks_visible: value.x_minor_ticks_visible,
y_minor_ticks_visible: value.y_minor_ticks_visible,
x_minor_tick_divisions: value.x_minor_tick_divisions,
y_minor_tick_divisions: value.y_minor_tick_divisions,
classic_mode: value.classic_mode,
axes_autolimit_mode: value.axes_autolimit_mode,
timezone: value.timezone,
date_converter: value.date_converter,
date_interval_multiples: value.date_interval_multiples,
lines_scale_dashes: value.lines_scale_dashes,
lines_dashed_pattern: value.lines_dashed_pattern.copy(),
lines_dashdot_pattern: value.lines_dashdot_pattern.copy(),
lines_dotted_pattern: value.lines_dotted_pattern.copy(),
date_autoformats: value.date_autoformats.copy(),
date_epoch: value.date_epoch,
color_cycle: value.color_cycle.copy(),
x_margin: value.x_margin,
y_margin: value.y_margin,
grid_visible: value.grid_visible,
grid_color: value.grid_color,
grid_linewidth: value.grid_linewidth,
}
}
///|
/// Restore the default tab10 cycle and 5% automatic margins.
pub fn reset() -> Unit {
current.val = default_rc_params()
}
///|
/// Return the configured default color cycle.
pub fn color_cycle() -> Array[String] {
current.val.color_cycle.copy()
}
///|
/// Replace the configured default color cycle.
pub fn set_color_cycle(colors : Array[String]) -> Unit raise @core.DataError {
validate_color_cycle(colors)
current.val.color_cycle.clear()
for color in colors {
current.val.color_cycle.push(color)
}
}
///|
/// Return the configured default x-axis margin.
pub fn x_margin() -> Double {
current.val.x_margin
}
///|
/// Replace the configured default x-axis margin.
pub fn set_x_margin(value : Double) -> Unit raise @core.DataError {
validate_margin(value)
current.val.x_margin = value
}
///|
/// Return the configured default y-axis margin.
pub fn y_margin() -> Double {
current.val.y_margin
}
///|
/// Replace the configured default y-axis margin.
pub fn set_y_margin(value : Double) -> Unit raise @core.DataError {
validate_margin(value)
current.val.y_margin = value
}
///|
/// Return whether newly created axes show major grid lines.
pub fn grid_visible() -> Bool {
current.val.grid_visible
}
///|
/// Return the default major grid color.
pub fn grid_color() -> String {
current.val.grid_color
}
///|
/// Return the default major grid linewidth.
pub fn grid_linewidth() -> Double {
current.val.grid_linewidth
}
///|
/// Replace the defaults used by newly created axes for major grid lines.
pub fn set_grid(
visible : Bool,
color : String,
linewidth : Double,
) -> Unit raise @core.DataError {
if color.length() == 0 {
raise @core.DataError::InvalidTicks(message="grid color must not be empty")
}
if linewidth.is_nan() || linewidth.is_inf() || linewidth <= 0.0 {
raise @core.DataError::InvalidTicks(
message="grid linewidth must be finite and positive",
)
}
current.val.grid_visible = visible
current.val.grid_color = color
current.val.grid_linewidth = linewidth
}
///|
/// Return a copy of the configured color cycle.
pub fn RcParams::color_cycle(self : RcParams) -> Array[String] {
self.color_cycle.copy()
}
///|
pub fn RcParams::x_margin(self : RcParams) -> Double {
self.x_margin
}
///|
pub fn RcParams::y_margin(self : RcParams) -> Double {
self.y_margin
}
///|
pub fn RcParams::grid_visible(self : RcParams) -> Bool {
self.grid_visible
}
///|
pub fn RcParams::grid_color(self : RcParams) -> String {
self.grid_color
}
///|
pub fn RcParams::grid_linewidth(self : RcParams) -> Double {
self.grid_linewidth
}
///|
/// Return the fallback origin used when the date package first selects an epoch.
pub fn date_epoch() -> String {
current.val.date_epoch
}
///|
/// Configure a validated UTC ISO fallback. An already selected date epoch is
/// unaffected, including when other configuration defaults are reset.
pub fn set_date_epoch(value : String) -> Unit raise @core.DataError {
match @date_epoch.parse(value) {
Ok(_) => current.val.date_epoch = value
Err(message) => raise @core.DataError::InvalidTicks(message~)
}
}
///|
pub fn RcParams::date_epoch(self : RcParams) -> String {
self.date_epoch
}
///|
/// Default behavior of MultipleLocator.view_limits: data or round_numbers.
pub fn axes_autolimit_mode() -> String {
current.val.axes_autolimit_mode
}
///|
pub fn set_axes_autolimit_mode(value : String) -> Unit raise @core.DataError {
if value != "data" && value != "round_numbers" {
raise @core.DataError::InvalidTicks(
message="axes.autolimit_mode must be data or round_numbers",
)
}
current.val.axes_autolimit_mode = value
}
///|
pub fn RcParams::axes_autolimit_mode(self : RcParams) -> String {
self.axes_autolimit_mode
}