Skip to content

Commit

Permalink
Display selected primer data in the seq and map views
Browse files Browse the repository at this point in the history
  • Loading branch information
David O'Connor committed Aug 29, 2024
1 parent 1007eec commit f690fd6
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 34 deletions.
43 changes: 41 additions & 2 deletions src/gui/circle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
navigation::NAV_BUTTON_COLOR,
select_feature,
seq_view::{COLOR_RE, COLOR_SEQ},
COL_SPACING, ROW_SPACING, SPLIT_SCREEN_MAX_HEIGHT,
COL_SPACING, PRIMER_FWD_COLOR, PRIMER_REV_COLOR, ROW_SPACING, SPLIT_SCREEN_MAX_HEIGHT,
},
primer::{Primer, PrimerDirection},
restriction_enzyme::{ReMatch, RestrictionEnzyme},
Expand Down Expand Up @@ -817,6 +817,45 @@ fn draw_feature_text(feature: &Feature, data: &CircleData, ui: &mut Ui) -> Vec<S
result
}

/// Similar to `draw_feature_text`.
fn draw_primer_text(primer: &Primer, data: &CircleData, ui: &mut Ui) -> Vec<Shape> {
let mut result = Vec::new();

let labels = vec![
primer.name.clone(),
primer.location_descrip(),
primer.description.clone().unwrap_or_default(),
seq_to_str(&primer.sequence),
];

// let color = match primer.direction {
// PrimerDirection::Forward => PRIMER_FWD_COLOR,
// PrimerDirection::Reverse => PRIMER_REV_COLOR,
// };
//
// todo: Rev or neutral A/R
let color = PRIMER_FWD_COLOR;

let mut i = 0; // Rows

for label in &labels {
result.push(draw_text(
label,
data.to_screen
* pos2(
data.center.x,
data.center.y + i as f32 * CENTER_TEXT_ROW_SPACING - 60.,
),
16.,
color,
ui,
)); // slightly below seq name, ui));
i += 1;
}

result
}

/// Draw text in the center of the circle; eg general plasmid information, or information
/// about a feature. This is the selected feature if available; then hovered-over if available;
/// then general plasmid information.
Expand All @@ -837,7 +876,7 @@ fn draw_center_text(data: &CircleData, state: &mut State, ui: &mut Ui) -> Vec<Sh
return result;
}
let primer = &state.generic.primers[*prim_i];
// todo
result.append(&mut draw_primer_text(primer, data, ui));
}
Selection::None => {
match &state.ui.feature_hover {
Expand Down
3 changes: 3 additions & 0 deletions src/gui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ pub const COL_SPACING: f32 = 30.;
// Note: This is basically working, but doesn't seem to reflect this scaling factor accurately.
pub const SPLIT_SCREEN_MAX_HEIGHT: f32 = 3.5;

pub const PRIMER_FWD_COLOR: Color32 = Color32::from_rgb(255, 0, 255);
pub const PRIMER_REV_COLOR: Color32 = Color32::from_rgb(0, 255, 0);

pub fn int_field(val: &mut usize, label: &str, ui: &mut Ui) {
ui.label(label);
let mut entry = val.to_string();
Expand Down
88 changes: 57 additions & 31 deletions src/gui/sequence.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! This module contains GUI code related to the sequence view.
use std::error::Error;

use eframe::egui::{text::CursorRange, Color32, Frame, RichText, ScrollArea, TextEdit, Ui};

// todo: monospace font for all seqs.
Expand All @@ -13,7 +15,7 @@ use crate::{
navigation::{page_seq_selector, page_seq_top_selector, PageSeq, PageSeqTop},
primer_table::primer_details,
seq_view::sequence_vis,
SPLIT_SCREEN_MAX_HEIGHT,
PRIMER_FWD_COLOR, SPLIT_SCREEN_MAX_HEIGHT,
},
primer::{Primer, PrimerData},
util::RangeIncl,
Expand Down Expand Up @@ -42,29 +44,36 @@ fn seq_editor_raw(state: &mut State, ui: &mut Ui) {
}

/// Displays text of the feature under the cursor, or selected, as required.
fn feature_text(feature: &Option<usize>, features: &[Feature], seq_len: usize, ui: &mut Ui) {
match feature {
Some(i) => {
if features.len() < *i + 1 {
eprintln!("Invalid hover feature");
return; // todo: Ideally set the feature to none.
}
let feature = &features[*i];
fn feature_text(i: usize, features: &[Feature], seq_len: usize, ui: &mut Ui) {
if features.len() < i + 1 {
eprintln!("Invalid selected feature");
return; // todo: Ideally set the feature to none.
}
let feature = &features[i];

ui.label(&feature.label); // todo: IDeally heading here, but it is currnetly causing display jumping.
ui.label(feature.location_descrip(seq_len));
let (r, g, b) = feature.color();
ui.label(
RichText::new(feature.feature_type.to_string()).color(Color32::from_rgb(r, g, b)),
);
ui.label(&feature.label);
ui.label(feature.location_descrip(seq_len));
let (r, g, b) = feature.color();
ui.label(RichText::new(feature.feature_type.to_string()).color(Color32::from_rgb(r, g, b)));

// todo?
for note in &feature.notes {
// ui.label(&format!("{}: {}", note.0, note.1));
}
}
None => (),
// todo?
for note in &feature.notes {
// ui.label(&format!("{}: {}", note.0, note.1));
}
}

fn primer_text(i: usize, primers: &[Primer], seq_len: usize, ui: &mut Ui) {
if primers.len() < i + 1 {
eprintln!("Invalid selected primer");
return; // todo: Ideally set the feature to none.
}
let primer = &primers[i];

ui.label(&primer.name);
ui.label(&primer.location_descrip());
ui.label(&primer.description.clone().unwrap_or_default());
// todo: Rev color A/R
ui.label(RichText::new(seq_to_str(&primer.sequence)).color(PRIMER_FWD_COLOR));
}

/// Add a toolbar to create a feature from selection, if appropriate.
Expand Down Expand Up @@ -224,18 +233,35 @@ pub fn seq_page(state: &mut State, ui: &mut Ui) {
ui.add_space(COL_SPACING);

let mut feature_to_disp = None;
if let Selection::Feature(i) = state.ui.selected_item {
feature_to_disp = Some(i);
} else if state.ui.feature_hover.is_some() {
feature_to_disp = Some(state.ui.feature_hover.unwrap());
let mut primer_to_disp = None;

match state.ui.selected_item {
Selection::Feature(i) => feature_to_disp = Some(i),
Selection::Primer(i) => primer_to_disp = Some(i),
Selection::None => {
if state.ui.feature_hover.is_some() {
feature_to_disp = Some(state.ui.feature_hover.unwrap());
}
}
}

feature_text(
&feature_to_disp,
&state.generic.features,
state.generic.seq.len(),
ui,
);
if let Some(feature_i) = feature_to_disp {
feature_text(
feature_i,
&state.generic.features,
state.generic.seq.len(),
ui,
);
}

if let Some(primer_i) = primer_to_disp {
primer_text(
primer_i,
&state.generic.primers,
state.generic.seq.len(),
ui,
);
}
});

ui.add_space(ROW_SPACING / 2.);
Expand Down
6 changes: 5 additions & 1 deletion src/melting_temp_calcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
//! and apply salt corrections based on user input concentrations of ions and primers.
//!
//! The calculations are based primarily on [SantaLucia & Hicks (2004)](https://pubmed.ncbi.nlm.nih.gov/15139820/)
//!
//! [This calculator from NorthWestern](http://biotools.nubic.northwestern.edu/OligoCalc.html) may be used
//! for QC TM, weight, and other properties. It includes detailed sources and methods.
use crate::{
primer::{calc_gc, IonConcentrations, MIN_PRIMER_LEN},
Expand Down Expand Up @@ -323,7 +326,8 @@ pub fn calc_tm(seq: &[Nucleotide], ion_concentrations: &IonConcentrations) -> Op

// We will assume saltcorr method 1-4 for now.
if let Some(sc) = salt_correction(seq, ion_concentrations) {
result += sc;
// todo: Put back! Evaluating our method.
// result += sc;

// for saltcorr 6/7:
// result = 1. / (1. / (result + 273.15) + sc) - 273.15
Expand Down
10 changes: 10 additions & 0 deletions src/primer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ impl Primer {
result
}

/// Formats the indexes, and size of this feature.
pub fn location_descrip(&self) -> String {
self.volatile
.matches
.iter()
.map(|match_| format!("{}..{}", match_.range.start, match_.range.end))
.collect::<Vec<String>>()
.join("; ")
}

/// Automatically select primer length based on quality score.
pub fn tune(&mut self, ion: &IonConcentrations) {
match self.volatile.tune_setting {
Expand Down

0 comments on commit f690fd6

Please sign in to comment.