Skip to content

Commit

Permalink
#22 Add relative plot functionality for artists
Browse files Browse the repository at this point in the history
  • Loading branch information
fsktom committed Mar 29, 2023
1 parent be411b4 commit 274f4b8
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 6 deletions.
8 changes: 8 additions & 0 deletions src/display/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,14 @@ fn gather_songs_with_album_date(
songs
}

/// Sums all plays in the given date frame
pub fn sum_plays(entries: &[SongEntry], start: &DateTime<Tz>, end: &DateTime<Tz>) -> usize {
entries
.iter()
.filter(|entry| is_between(&entry.timestamp, start, end))
.count()
}

/// Checks if the given date is between (or equal) to the other two dates
fn is_between(date: &DateTime<Tz>, start: &DateTime<Tz>, end: &DateTime<Tz>) -> bool {
date.ge(start) && date.le(end)
Expand Down
9 changes: 8 additions & 1 deletion src/plot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ use plotly::{Layout, Plot, Scatter};
/// Responsible for plotting absolute plots
pub mod absolute;

/// Responsible for plotting plots relative to sum of plays
pub mod relative;

/// Creates a plot in a `plots/` folder
///
/// Then opens it in the browser
fn create_plot(dates: Vec<i64>, plays: Vec<usize>, title: &str) {
fn create_plot<Y>(dates: Vec<i64>, plays: Vec<Y>, title: &str)
where
Y: serde::Serialize + Clone + 'static,
// see https://github.com/igiagkiozis/plotly/blob/8903ff03ce9e8183624c40ccf7ddf863799cb92e/plotly/src/traces/scatter.rs#L292-L303
{
let mut plot = Plot::new();
// TODO: make it display actual dates instead of UNIX timestamps xd
plot.add_trace(Scatter::new(dates, plays).name(title));
Expand Down
26 changes: 26 additions & 0 deletions src/plot/relative.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use super::{create_plot, find_dates};
use crate::display::date;
use crate::types::{Artist, SongEntries};

/// Creates a plot of the amount of plays of an [`Artist`] relative to all plays
///
/// Opens the plot in the browser
pub fn artist(entries: &SongEntries, art: &Artist) {
let mut times = Vec::<i64>::new();
// percentages relative to the sum of all plays
let mut plays = Vec::<f64>::new();

let dates = find_dates(entries, art, true);

let start = dates.first().unwrap();
let sum_start = &entries.first_date();

for date in &dates {
times.push(date.timestamp());
let sum_of_plays = date::gather_artist(entries, art, start, date) as f64;
let sum_of_all_plays = date::sum_plays(entries, &sum_start, date) as f64;
plays.push(sum_of_plays / sum_of_all_plays);
}

create_plot(times, plays, format!("{art} - relative").as_str());
}
13 changes: 13 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ impl SongEntries {
Ok(SongEntries(parse::parse(paths)?))
}

/// Returns the date of the first (time-wise) occurrence of any [`SongEntry`]
pub fn first_date(&self) -> DateTime<Tz> {
self.iter()
.min_by(|x, y| x.timestamp.cmp(&y.timestamp))
.unwrap()
.timestamp
}

/// Prints the top `num` of an `asp`
///
/// * `asp` - [`Aspect::Songs`] (affected by [`display::SUM_ALBUMS`]) for top songs, [`Aspect::Albums`] for top albums and
Expand Down Expand Up @@ -289,6 +297,11 @@ impl SongEntries {
plot::absolute::artist(self, art);
}

/// Creates a plot of the artist relative to the total amount of plays
pub fn plot_artist_relative(&self, art: &Artist) {
plot::relative::artist(self, art);
}

/// Adds search capability
///
/// Use with methods from [`Find`]: [`.artist()`](Find::artist()), [`.album()`](Find::album()),
Expand Down
15 changes: 15 additions & 0 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ fn match_input(
"print top albums" | "ptalbs" => match_print_top(entries, rl, &Aspect::Albums)?,
"print top songs" | "ptsons" => match_print_top(entries, rl, &Aspect::Songs)?,
"plot artist" | "gart" => match_plot_artist(entries, rl)?,
"plot artist relative" | "gartr" => match_plot_artist_relative(entries, rl)?,
// when you press ENTER -> nothing happens, new prompt
"" => (),
_ => {
Expand Down Expand Up @@ -440,6 +441,20 @@ fn match_plot_artist(
Ok(())
}

/// Used by [`match_input()`] for `plot artist relative` command
fn match_plot_artist_relative(
entries: &SongEntries,
rl: &mut Editor<ShellHelper, FileHistory>,
) -> Result<(), Box<dyn Error>> {
// 1st prompt: artist name
println!("Artist name?");
let usr_input_art = rl.readline(PROMPT_MAIN)?;
let art = entries.find().artist(&usr_input_art)?;

entries.plot_artist_relative(&art);
Ok(())
}

/// used by `*_date` functions in this module for when the user inputs a date
///
/// # Arguments
Expand Down
18 changes: 13 additions & 5 deletions src/ui/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,20 @@ fn print_top_commands<'a>() -> Vec<[&'a str; 3]> {

/// Returns graph commands
fn plot_commands<'a>() -> Vec<[&'a str; 3]> {
vec![[
"plot artist",
"gart",
"creates a plot of the absolute amount of plays of the given artist
vec![
[
"plot artist",
"gart",
"creates a plot of the absolute amount of plays of the given artist
and opens it in the web browser",
]]
],
[
"plot artist relative",
"gartr",
"creates a plot of the amount of plays of the given artist
relative to all plays and opens it in the web browser",
],
]
}

#[cfg(test)]
Expand Down

0 comments on commit 274f4b8

Please sign in to comment.