diff --git a/randquik/cli.py b/randquik/cli.py index b248227..b11765c 100644 --- a/randquik/cli.py +++ b/randquik/cli.py @@ -165,7 +165,6 @@ def _main(): workers=workers, dry=args.dry, quiet=args.quiet, - seed_for_display=seed_for_display, action=action, ) diff --git a/randquik/progress.py b/randquik/progress.py index 9a5543d..f069aff 100644 --- a/randquik/progress.py +++ b/randquik/progress.py @@ -30,13 +30,11 @@ class ProgressDisplay: start_time: float, state: dict, infinite: bool | None = None, - seed: str | None = None, ): self.total_bytes = total_bytes self.start_time = start_time self.state = state # Must have 'written' key self.infinite = infinite if infinite is not None else total_bytes is None - self.seed = seed self.active = sys.stderr.isatty() self._stop = threading.Event() self._thread = None @@ -179,12 +177,11 @@ class ProgressDisplay: spinner = "◐◓◑◒"[int(elapsed * 4) % 4] written_gb = written / 1_000_000_000 current_speed = instant_speed / 1_000_000_000 - seed_hint = f" \x1b[2m-s {self.seed}\x1b[0m" if self.seed else "" header = ( f" \x1b[1;36mRandQuik {spinner}\x1b[0m " - f"\x1b[2m│\x1b[0m {written_gb:6.2f}/∞ GB " + f"\x1b[2m│\x1b[0m {written_gb:6.2f} GB \x1b[2m∞\x1b[0m " f"\x1b[2m@\x1b[0m {current_speed:5.2f} GB/s " - f"\x1b[2m│\x1b[0m {format_time(elapsed):>8}{seed_hint}" + f"\x1b[2m│\x1b[0m {format_time(elapsed):>8}" ) lines.append(header) lines.append("") @@ -230,10 +227,9 @@ class ProgressDisplay: # Add GB/s label above the graph lines.append(" \x1b[36mGB/s\x1b[0m") - # Compute nice Y-axis tick values - nice_ticks = set(self._nice_y_ticks(scale_max)) - labeled_values = set() # Track which tick values have been labeled - tolerance = scale_max / (graph_rows - 1) / 2 if graph_rows > 1 else 0.1 + # Compute nice Y-axis tick values and map each to its best row + nice_ticks = self._nice_y_ticks(scale_max, graph_rows) + row_labels = self._assign_ticks_to_rows(nice_ticks, scale_max, graph_rows) for row in range(graph_rows): graph_line = self._render_graph_row( @@ -246,16 +242,8 @@ class ProgressDisplay: ) graph_line = graph_line.ljust(graph_width) - # Y-axis labels - only label nice tick values - row_value = ( - scale_max * (graph_rows - 1 - row) / (graph_rows - 1) if graph_rows > 1 else 0 - ) - label = " " - for tick in nice_ticks: - if abs(row_value - tick) < tolerance and tick not in labeled_values: - label = f"{self._format_label(tick):>4}" - labeled_values.add(tick) - break + # Y-axis label from pre-computed mapping + label = row_labels.get(row, " ") lines.append(f" \x1b[36m{label}\x1b[0m \x1b[33m{graph_line}\x1b[0m") # Time axis @@ -289,14 +277,19 @@ class ProgressDisplay: else: return f"{val:.1f}" - def _nice_y_ticks(self, scale_max: float, max_ticks: int = 5) -> list[float]: + def _nice_y_ticks(self, scale_max: float, graph_rows: int = 10) -> list[float]: """Return nice Y-axis tick values from 0 to scale_max. - Chooses a nice interval (1, 2, 5 × 10^N) that gives roughly max_ticks labels. + Chooses a nice interval (1, 2, 5 × 10^N) that gives labels with + sufficient spacing (at least 3 rows between labels). """ if scale_max <= 0: return [0] + # We want at least 5 empty rows between labels for readability + min_row_spacing = 5 + max_ticks = max(2, graph_rows // min_row_spacing) + # Nice intervals: 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, ... nice_bases = [1, 2, 5] best_interval = scale_max @@ -319,6 +312,31 @@ class ProgressDisplay: val += best_interval return ticks + def _assign_ticks_to_rows( + self, ticks: list[float], scale_max: float, graph_rows: int + ) -> dict[int, str]: + """Assign each tick to the row closest to its value. + + Returns a dict mapping row index to formatted label string. + Each tick is assigned to exactly one row. + """ + row_labels: dict[int, str] = {} + if graph_rows <= 1 or scale_max <= 0: + return {0: f"{self._format_label(ticks[0] if ticks else 0):>4}"} + + for tick in ticks: + # Calculate which row this tick value corresponds to + # Row 0 is top (scale_max), row graph_rows-1 is bottom (0) + exact_row = (1 - tick / scale_max) * (graph_rows - 1) + best_row = round(exact_row) + best_row = max(0, min(graph_rows - 1, best_row)) + + # Only assign if row is not already taken (first tick wins) + if best_row not in row_labels: + row_labels[best_row] = f"{self._format_label(tick):>4}" + + return row_labels + def _build_infinite_time_axis(self, graph_width: int, scale_time: float) -> list[str]: """Build time axis for infinite mode with nice interval labels. @@ -457,12 +475,11 @@ class ProgressDisplay: current_speed = instant_speed / 1_000_000_000 written_gb = written / 1_000_000_000 total_gb = self.total_bytes / 1_000_000_000 - seed_hint = f" \x1b[2m-s {self.seed}\x1b[0m" if self.seed else "" header = ( f" \x1b[1;36mRandQuik {spinner}\x1b[0m " f"\x1b[2m│\x1b[0m {written_gb:6.2f}\x1b[2m/\x1b[0m{total_gb:.2f} GB " f"\x1b[2m@\x1b[0m {current_speed:5.2f} GB/s " - f"ETA {format_time(eta):>8}{seed_hint}" + f"ETA {format_time(eta):>8}" ) lines.append(header) lines.append("") @@ -478,10 +495,9 @@ class ProgressDisplay: # Add GB/s label above the graph lines.append(" \x1b[36mGB/s\x1b[0m") - # Compute nice Y-axis tick values - nice_ticks = set(self._nice_y_ticks(scale_max)) - labeled_values = set() # Track which tick values have been labeled - tolerance = scale_max / (graph_rows - 1) / 2 if graph_rows > 1 else 0.1 + # Compute nice Y-axis tick values and map each to its best row + nice_ticks = self._nice_y_ticks(scale_max, graph_rows) + row_labels = self._assign_ticks_to_rows(nice_ticks, scale_max, graph_rows) for row in range(graph_rows): graph_line = self._render_graph_row( @@ -492,16 +508,8 @@ class ProgressDisplay: graph_width, avg_speed_gbs, ) - # Y-axis labels - only label nice tick values - row_value = ( - scale_max * (graph_rows - 1 - row) / (graph_rows - 1) if graph_rows > 1 else 0 - ) - label = " " - for tick in nice_ticks: - if abs(row_value - tick) < tolerance and tick not in labeled_values: - label = f"{self._format_label(tick):>4}" - labeled_values.add(tick) - break + # Y-axis label from pre-computed mapping + label = row_labels.get(row, " ") lines.append(f" \x1b[36m{label}\x1b[0m \x1b[33m{graph_line}\x1b[0m") # Time labels on X-axis with nice intervals diff --git a/randquik/workers.py b/randquik/workers.py index 56f5161..be888cc 100644 --- a/randquik/workers.py +++ b/randquik/workers.py @@ -271,7 +271,6 @@ def run( workers: int = 1, dry: bool = False, quiet: bool = False, - seed_for_display: str | None = None, action: str = "wrote", continue_cmd: str | None = None, ) -> RunResult: @@ -296,7 +295,6 @@ def run( start_time, progress_state, infinite=infinite, - seed=seed_for_display, ) if not quiet: progress.start()