Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
alicja-januszkiewicz committed Mar 15, 2023
1 parent 7a43f9d commit f03f90e
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 12 deletions.
2 changes: 2 additions & 0 deletions polars/polars-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
pub(crate) const FMT_MAX_COLS: &str = "POLARS_FMT_MAX_COLS";
pub(crate) const FMT_MAX_ROWS: &str = "POLARS_FMT_MAX_ROWS";
pub(crate) const FMT_STR_LEN: &str = "POLARS_FMT_STR_LEN";
pub(crate) const FMT_FLOAT_PRECISION: &str = "POLARS_FMT_FLOAT_PRECISION";
pub(crate) const FMT_TABLE_CELL_ALIGNMENT: &str = "POLARS_FMT_TABLE_CELL_ALIGNMENT";
pub(crate) const FMT_TABLE_CELL_NUMERIC_ALIGNMENT: &str = "POLARS_FMT_TABLE_CELL_NUMERIC_ALIGNMENT";
pub(crate) const FMT_TABLE_DATAFRAME_SHAPE_BELOW: &str = "POLARS_FMT_TABLE_DATAFRAME_SHAPE_BELOW";
pub(crate) const FMT_TABLE_FORMATTING: &str = "POLARS_FMT_TABLE_FORMATTING";
pub(crate) const FMT_TABLE_HIDE_COLUMN_DATA_TYPES: &str = "POLARS_FMT_TABLE_HIDE_COLUMN_DATA_TYPES";
Expand Down
45 changes: 34 additions & 11 deletions polars/polars-core/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,25 +554,26 @@ impl Display for DataFrame {
}

// set alignment of cells, if defined
if std::env::var(FMT_TABLE_CELL_ALIGNMENT).is_ok() {
if std::env::var(FMT_TABLE_CELL_ALIGNMENT).is_ok()
| std::env::var(FMT_TABLE_CELL_NUMERIC_ALIGNMENT).is_ok()
{
let str_preset = std::env::var(FMT_TABLE_CELL_ALIGNMENT)
.unwrap_or_else(|_| "DEFAULT".to_string());
for column in table.column_iter_mut() {
match str_preset.as_str() {
let num_preset = std::env::var(FMT_TABLE_CELL_NUMERIC_ALIGNMENT)
.unwrap_or_else(|_| str_preset.to_string());
for (column_index, column) in table.column_iter_mut().enumerate() {
let dtype = fields[column_index].data_type();
let mut preset = str_preset.as_str();
if dtype.to_physical().is_numeric() {
preset = num_preset.as_str();
}
match preset {
"RIGHT" => column.set_cell_alignment(CellAlignment::Right),
"LEFT" => column.set_cell_alignment(CellAlignment::Left),
"CENTER" => column.set_cell_alignment(CellAlignment::Center),
_ => {}
}
}
} else {
// set default alignment to right for numeric cells
for (column_index, column) in table.column_iter_mut().enumerate() {
let dtype = fields[column_index].data_type();
if dtype.to_physical().is_numeric() {
column.set_cell_alignment(CellAlignment::Right)
};
}
}

// establish 'shape' information (above/below/hidden)
Expand Down Expand Up @@ -609,10 +610,32 @@ fn fmt_integer<T: Num + NumCast + Display>(
const SCIENTIFIC_BOUND: f64 = 999999.0;
fn fmt_float<T: Num + NumCast>(f: &mut Formatter<'_>, width: usize, v: T) -> fmt::Result {
let v: f64 = NumCast::from(v).unwrap();

match get_float_fmt() {
FloatFmt::Full => {
println!("float format is full");
}
FloatFmt::Mixed => {
println!("float format is mixed");
}
}

if matches!(get_float_fmt(), FloatFmt::Full) {
return write!(f, "{v:>width$}");
}

if let Ok(precision) = std::env::var(FMT_FLOAT_PRECISION)
.as_deref()
.unwrap_or("")
.parse::<usize>()
{
return write!(f, "{v:>width$.precision$e}");
// if (format!("{v}").len() > 9) & (!(0.000001..=SCIENTIFIC_BOUND).contains(&v.abs()) | (v.abs() > SCIENTIFIC_BOUND)) {
// return write!(f, "{v:>width$.precision$e}");
// }
// return write!(f, "{v:>width$.precision$}");
}

// show integers as 0.0, 1.0 ... 101.0
if v.fract() == 0.0 && v.abs() < SCIENTIFIC_BOUND {
write!(f, "{v:>width$.1}")
Expand Down
57 changes: 56 additions & 1 deletion py-polars/polars/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"POLARS_TABLE_WIDTH",
"POLARS_VERBOSE",
"POLARS_ACTIVATE_DECIMAL",
"POLARS_FMT_FLOAT_PRECISION",
"POLARS_STREAMING_CHUNK_SIZE",
}

Expand Down Expand Up @@ -243,6 +244,46 @@ def set_tbl_cell_alignment(
os.environ["POLARS_FMT_TABLE_CELL_ALIGNMENT"] = format
return cls

@classmethod
def set_tbl_cell_numeric_alignment(
cls, format: Literal["LEFT", "CENTER", "RIGHT"]
) -> type[Config]:
"""
Set table cell alignment for numeric columns.
Parameters
----------
format : str
* "LEFT": left aligned
* "CENTER": center aligned
* "RIGHT": right aligned
Examples
--------
>>> df = pl.DataFrame(
... {"column_abc": [11, 2, 333], "column_xyz": [True, False, True]}
... )
>>> pl.Config.set_tbl_cell_numeric_alignment("RIGHT") # doctest: +SKIP
# ...
# shape: (3, 2)
# ┌────────────┬────────────┐
# │ column_abc ┆ column_xyz │
# │ --- ┆ --- │
# │ i64 ┆ bool │
# ╞════════════╪════════════╡
# │ 11 ┆ true │
# │ 2 ┆ false │
# │ 333 ┆ true │
# └────────────┴────────────┘
Raises
------
KeyError: if alignment string not recognised.
"""
os.environ["POLARS_FMT_TABLE_CELL_NUMERIC_ALIGNMENT"] = format
return cls

@classmethod
def set_tbl_cols(cls, n: int) -> type[Config]:
"""
Expand Down Expand Up @@ -573,13 +614,27 @@ def set_fmt_float(cls, fmt: str = "mixed") -> type[Config]:
_set_float_fmt(fmt)
return cls

@classmethod
def set_float_precision(cls, precision: int = 1) -> type[Config]:
"""
Control how floating point values are displayed.
Parameters
----------
precision : int
Number of decimal places to display
"""
os.environ["POLARS_FMT_FLOAT_PRECISION"] = str(precision)
return cls

@classmethod
def activate_decimals(cls) -> type[Config]:
"""
Activate ``Decimal`` data types.
This is temporary setting that will be removed later once
``Decimal`` type stabilize. This happens without it being
``Decimal`` type stabilizes. This happens without it being
considered a breaking change.
Currently, ``Decimal`` types are in alpha stage.
Expand Down
51 changes: 51 additions & 0 deletions py-polars/tests/unit/test_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,57 @@ def test_shape_below_table_and_inlined_dtype() -> None:
)


def test_numeric_right_alignment() -> None:
pl.Config.set_tbl_cell_numeric_alignment("RIGHT")
pl.Config.set_float_precision(3)

df = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})
assert (
str(df) == "shape: (3, 3)\n"
"┌─────┬─────┬─────┐\n"
"│ a ┆ b ┆ c │\n"
"│ --- ┆ --- ┆ --- │\n"
"│ i64 ┆ i64 ┆ i64 │\n"
"╞═════╪═════╪═════╡\n"
"│ 1 ┆ 4 ┆ 7 │\n"
"│ 2 ┆ 5 ┆ 8 │\n"
"│ 3 ┆ 6 ┆ 9 │\n"
"└─────┴─────┴─────┘"
)

df = pl.DataFrame(
{"a": [1.1, 2.22, 3.333], "b": [4.0, 5.0, 6.0], "c": [7.0, 8.0, 9.0]}
)

pl.Config.set_fmt_float("mixed")
assert (
str(df) == "shape: (3, 3)\n"
"┌─────────┬─────────┬─────────┐\n"
"│ a ┆ b ┆ c │\n"
"│ --- ┆ --- ┆ --- │\n"
"│ f64 ┆ f64 ┆ f64 │\n"
"╞═════════╪═════════╪═════════╡\n"
"│ 1.100e0 ┆ 4.000e0 ┆ 7.000e0 │\n"
"│ 2.220e0 ┆ 5.000e0 ┆ 8.000e0 │\n"
"│ 3.333e0 ┆ 6.000e0 ┆ 9.000e0 │\n"
"└─────────┴─────────┴─────────┘"
)

pl.Config.set_fmt_float("full")
assert (
str(df) == "shape: (3, 3)\n"
"┌───────┬─────┬─────┐\n"
"│ a ┆ b ┆ c │\n"
"│ --- ┆ --- ┆ --- │\n"
"│ f64 ┆ f64 ┆ f64 │\n"
"╞═══════╪═════╪═════╡\n"
"│ 1.1 ┆ 4 ┆ 7 │\n"
"│ 2.22 ┆ 5 ┆ 8 │\n"
"│ 3.333 ┆ 6 ┆ 9 │\n"
"└───────┴─────┴─────┘"
)


def test_string_cache() -> None:
df1 = pl.DataFrame({"a": ["foo", "bar", "ham"], "b": [1, 2, 3]})
df2 = pl.DataFrame({"a": ["foo", "spam", "eggs"], "c": [3, 2, 2]})
Expand Down

0 comments on commit f03f90e

Please sign in to comment.