Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "kmutnb-phylab-plotter"
version = "0.1.0"
edition = "2021"
edition = "2024"
license = "Apache-2.0"
description = "Terminal graph-paper plotter for physics lab data"

Expand Down
49 changes: 23 additions & 26 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ratatui::{
use crate::{
app::ScaleSettings,
data::LabPoint,
stats::{linear_regression, Regression},
stats::{Regression, linear_regression},
};

const BRAILLE_WIDTH: usize = 2;
Expand Down Expand Up @@ -457,28 +457,28 @@ impl PlotRenderer {
}
graph.set(axis_col, axis_row, '+', Layer::Axis);

if self.options.show_fit {
if let Some(regression) = linear_regression(&self.points) {
for col in self.area.x..self.area.x + self.area.width {
let x = self.cell_to_x(col);
let y = regression.slope * x + regression.intercept;
if let Some(row) = self.y_to_cell(y) {
graph.set(col, row, '.', Layer::FitLine);
}
if self.options.show_fit
&& let Some(regression) = linear_regression(&self.points)
{
for col in self.area.x..self.area.x + self.area.width {
let x = self.cell_to_x(col);
let y = regression.slope * x + regression.intercept;
if let Some(row) = self.y_to_cell(y) {
graph.set(col, row, '.', Layer::FitLine);
}
}
}

if let Some((x, y)) = self.options.crosshair {
if let (Some(col), Some(row)) = (self.x_to_cell(x), self.y_to_cell(y)) {
for c in self.area.x..self.area.x + self.area.width {
graph.set(c, row, '-', Layer::Crosshair);
}
for r in self.area.y..self.area.y + self.area.height {
graph.set(col, r, '|', Layer::Crosshair);
}
graph.set(col, row, 'X', Layer::Crosshair);
if let Some((x, y)) = self.options.crosshair
&& let (Some(col), Some(row)) = (self.x_to_cell(x), self.y_to_cell(y))
{
for c in self.area.x..self.area.x + self.area.width {
graph.set(c, row, '-', Layer::Crosshair);
}
for r in self.area.y..self.area.y + self.area.height {
graph.set(col, r, '|', Layer::Crosshair);
}
graph.set(col, row, 'X', Layer::Crosshair);
}

for point in &self.points {
Expand Down Expand Up @@ -901,11 +901,7 @@ fn nice_step(raw: f64) -> f64 {

fn clean_float(value: f64) -> f64 {
let rounded = (value * 1e12).round() / 1e12;
if rounded.abs() < 1e-12 {
0.0
} else {
rounded
}
if rounded.abs() < 1e-12 { 0.0 } else { rounded }
}

fn major_values(min: f64, max: f64, step: f64) -> Vec<f64> {
Expand Down Expand Up @@ -989,9 +985,10 @@ mod tests {
);
let text = lines.join("\n");

assert!(text
.chars()
.any(|ch| ('\u{2800}'..='\u{28ff}').contains(&ch)));
assert!(
text.chars()
.any(|ch| ('\u{2800}'..='\u{28ff}').contains(&ch))
);
assert!(!text.contains("|||||"));
assert!(!text.contains("!!!!!"));
assert!(!text.contains(":::::"));
Expand Down
9 changes: 5 additions & 4 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,11 @@ fn handle_scale_input(app: &mut App, key: KeyEvent) -> bool {
}
}
KeyCode::Char(ch) => {
if let Some(editor) = &mut app.scale_editor {
if !key.modifiers.contains(KeyModifiers::CONTROL) && is_scale_char(ch) {
editor.buffers[editor.selected].push(ch);
}
if let Some(editor) = &mut app.scale_editor
&& !key.modifiers.contains(KeyModifiers::CONTROL)
&& is_scale_char(ch)
{
editor.buffers[editor.selected].push(ch);
}
}
_ => {}
Expand Down
15 changes: 7 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use anyhow::Result;
use crossterm::{
event::{self, Event},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
};
use kmutnb_phylab_plotter::{app::App, file_io, input, ui};
use ratatui::{backend::CrosstermBackend, Terminal};
use ratatui::{Terminal, backend::CrosstermBackend};

fn main() -> Result<()> {
let arg_path = env::args_os().nth(1).map(PathBuf::from);
Expand Down Expand Up @@ -53,12 +53,11 @@ fn run(terminal: &mut Terminal<CrosstermBackend<Stdout>>, app: &mut App) -> Resu
loop {
terminal.draw(|frame| ui::render(frame, app))?;

if event::poll(Duration::from_millis(200))? {
if let Event::Key(key) = event::read()? {
if !input::handle_key(app, key) {
break;
}
}
if event::poll(Duration::from_millis(200))?
&& let Event::Key(key) = event::read()?
&& !input::handle_key(app, key)
{
break;
}
}

Expand Down
23 changes: 17 additions & 6 deletions src/ui.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use ratatui::{
Frame,
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Cell, Clear, Paragraph, Row, Table, Wrap},
Frame,
};

use crate::{
Expand Down Expand Up @@ -236,7 +236,9 @@ fn render_status(frame: &mut Frame, app: &App, area: Rect) {
.map(|path| path.display().to_string())
.unwrap_or_else(|| "unsaved: lab_data.csv".to_string());
let help = match app.mode {
Mode::Normal => "?: help | i edit | a row | A col | d delete | X swap axes | s save | o open | S scale | G paper | q quit",
Mode::Normal => {
"?: help | i edit | a row | A col | d delete | X swap axes | s save | o open | S scale | G paper | q quit"
}
Mode::Scale => "Enter apply | u auto scale | Esc cancel | j/k field",
_ => "Enter confirm | Esc cancel",
};
Expand All @@ -256,15 +258,24 @@ fn render_help(frame: &mut Frame, area: Rect) {
let popup = centered_rect(area, 76, 24);
frame.render_widget(Clear, popup);
let text = vec![
Line::styled("Physics Lab Plotter Help", Style::default().add_modifier(Modifier::BOLD)),
Line::styled(
"Physics Lab Plotter Help",
Style::default().add_modifier(Modifier::BOLD),
),
Line::from(""),
Line::from("Navigation: h/j/k/l move table selection or graph crosshair, t focus table, g focus graph"),
Line::from(
"Navigation: h/j/k/l move table selection or graph crosshair, t focus table, g focus graph",
),
Line::from("Data: i edit cell, a add row, A add column, d delete row, r rename column"),
Line::from("Files: s save CSV, o open CSV, q quit"),
Line::from("Graph: f toggle best-fit line, X swap axes, G graph paper mode, c toggle crosshair"),
Line::from(
"Graph: f toggle best-fit line, X swap axes, G graph paper mode, c toggle crosshair",
),
Line::from("Scale: S set manual scale, u return to auto scale while in scale dialog"),
Line::from(""),
Line::from("Invalid or blank x/y values are shown in red in the table and ignored by fit/plot."),
Line::from(
"Invalid or blank x/y values are shown in red in the table and ignored by fit/plot.",
),
Line::from(
"Manual scale fields: x min, x max, y min, y max, x major, y major, minor divisions.",
),
Expand Down
Loading