Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REQUEST] Support width-aware number formatting #3522

Open
skeggse opened this issue Oct 5, 2024 · 1 comment
Open

[REQUEST] Support width-aware number formatting #3522

skeggse opened this issue Oct 5, 2024 · 1 comment

Comments

@skeggse
Copy link

skeggse commented Oct 5, 2024

Have you checked the issues for a similar suggestions?

Yes, but I'm not certain I didn't miss a relevant issue.

How would you improve Rich?

I'd like to improve the rendering for reviewing tables of accounting data at a glance. Numeric amounts are easy to skim (e.g. for order of magnitude) when they're right-aligned, but the inclusion of a $ makes it harder to separate the numbers from the units. Left-aligning the columns avoids the dollar signs becoming noise at the cost of making the numbers harder to skim.

I'd love to be able to either specify left-aligned units in the column itself or to be able to compose together to different pieces of text with different alignments on the same line/row.

In the following example, the suboptimal alignment is visible:

# example.py
from fractions import Fraction

from rich.console import Console
from rich.table import Table

entries = [
    (Fraction("10"), Fraction("20.54")),
    (Fraction("933"), Fraction("44.47")),
]

table = Table(title="Investments", show_edge=False)

table.add_column("Lot GUID")
table.add_column("Lot ID", no_wrap=True)
table.add_column("Shares", justify="right")
table.add_column("Cost Basis", justify="right")
table.add_column("Total Basis", justify="right")

for shares, basis in entries:
    table.add_row(
        "ABC",
        "2024-09-28",
        f"{shares:,.2f}",
        f"${basis:,.4f}",
        f"${basis * shares:,.2f}",
    )

console = Console()
console.print(table)
$ python example.py
                        Investments
 Lot GUID │ Lot ID     │ Shares │ Cost Basis │ Total Basis
──────────┼────────────┼────────┼────────────┼─────────────
 ABC      │ 2024-09-28 │  10.00 │   $20.5400 │     $205.40
 ABC      │ 2024-09-28 │ 933.00 │   $44.4700 │  $41,490.51

Ideally, I could ideally produce a table that looks like

$ python example.py
                        Investments
 Lot GUID │ Lot ID     │ Shares │ Cost Basis │ Total Basis
──────────┼────────────┼────────┼────────────┼─────────────
 ABC      │ 2024-09-28 │  10.00 │ $  20.5400 │ $    205.40
 ABC      │ 2024-09-28 │ 933.00 │ $  44.4700 │ $ 41,490.51

I tried Group(Align("$"), Align("41,490.51", align="right")), which produces the suboptimal:

Group-align rendering implementation:
from fractions import Fraction

from rich.align import Align
from rich.console import Console, Group
from rich.table import Table

entries = [
    (Fraction("10"), Fraction("20.54")),
    (Fraction("933"), Fraction("44.47")),
]

table = Table(title="Investments", show_edge=False)

table.add_column("Lot GUID")
table.add_column("Lot ID", no_wrap=True)
table.add_column("Shares", justify="right")
table.add_column("Cost Basis", justify="right")
table.add_column("Total Basis", justify="right")

for shares, basis in entries:
    table.add_row(
        "ABC",
        "2024-09-28",
        f"{shares:,.2f}",
        Group(Align("$"), Align(f"${basis:,.4f}", align="right")),
        Group(Align("$"), Align(f"${basis * shares:,.2f}", align="right")),
    )

console = Console()
console.print(table)
                        Investments
 Lot GUID │ Lot ID     │ Shares │ Cost Basis │ Total Basis
──────────┼────────────┼────────┼────────────┼─────────────
 ABC      │ 2024-09-28 │  10.00 │ $          │ $
          │            │        │   $20.5400 │     $205.40
 ABC      │ 2024-09-28 │ 933.00 │ $          │ $
          │            │        │   $44.4700 │  $41,490.51

I also tried a Layout-based approach, which produces the following giant wall of whitespace:

Layout-based rendering implementation
from fractions import Fraction

from rich.align import Align
from rich.console import Console
from rich.layout import Layout
from rich.table import Table


def format_dollars(value: Fraction):
    layout = Layout()
    dollar_sign = Layout("$")
    dollar_sign.size = 1
    layout.split_row(dollar_sign, Layout(Align(f"{value:,.2f}", align="right")))
    layout.size = 1
    return layout


entries = [
    (Fraction("10"), Fraction("20.54")),
    (Fraction("933"), Fraction("44.47")),
]

table = Table(title="Investments", show_edge=False)

table.add_column("Lot GUID")
table.add_column("Lot ID", no_wrap=True)
table.add_column("Shares", justify="right")
table.add_column("Cost Basis", justify="right")
table.add_column("Total Basis", justify="right")

for shares, basis in entries:
    table.add_row(
        "ABC",
        "2024-09-28",
        f"{shares:,.2f}",
        format_dollars(basis),
        format_dollars(basis * shares),
    )

console = Console()
console.print(table)
Layout-based rendering output
                                                      Investments
 Lot GUID │ Lot ID     │ Shares │                                Cost Basis │                              Total Basis
──────────┼────────────┼────────┼───────────────────────────────────────────┼──────────────────────────────────────────
 ABC      │ 2024-09-28 │  10.00 │ $                                   20.54 │ $                                 205.40
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
 ABC      │ 2024-09-28 │ 933.00 │ $                                   44.47 │ $                              41,490.51
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │
          │            │        │                                           │

A few ideal solutions for my use case:

  • add console markup syntax for alignment (e.g. [left]$[/][right]41,490.51[/])
  • add explicit column unit support (suffix units like °C are already well-supported because you can just right-align the entire column)
  • support Align renderables in a single Group without introducing extra lines

In addition to this specific formulation, I'd also love to be able to render negatives in a similar fashion:

                               Investments
 Lot GUID │ Lot ID     │ Shares │ Cost Basis │ Total Basis │   Gain(Loss)
──────────┼────────────┼────────┼────────────┼─────────────┼──────────────
 ABC      │ 2024-09-28 │  10.00 │   $20.5400 │     $205.40 │ ($    24.00)
 ABC      │ 2024-09-28 │ 933.00 │   $44.4700 │  $41,490.51 │ ($24,565.89)

Related:

Copy link

github-actions bot commented Oct 5, 2024

We found the following entry in the FAQ which you may find helpful:

Feel free to close this issue if you found an answer in the FAQ. Otherwise, please give us a little time to review.

This is an automated reply, generated by FAQtory

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant