Add some doc comments to lib
Gitea Scan/plate-tool/pipeline/head This commit looks good
Details
Gitea Scan/plate-tool/pipeline/head This commit looks good
Details
This commit is contained in:
parent
94386a0485
commit
ce6e88a347
|
@ -2,9 +2,10 @@ use serde::Serialize;
|
|||
|
||||
use super::TransferRecord;
|
||||
|
||||
// Format preferred by the Echo Client when using the Pick-List function.
|
||||
// Note that this does not export plate info!
|
||||
// Exports of this type should combine all transfers between the two actively selected plates.
|
||||
/// Format preferred by the Echo Client when using the Pick-List function.
|
||||
///
|
||||
/// Note that this does not export plate info!
|
||||
/// Exports of this type should combine all transfers between the two actively selected plates.
|
||||
#[derive(Serialize, Debug)]
|
||||
pub struct EchoClientTransferRecord {
|
||||
#[serde(rename = "SrcWell")]
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
//! Auto module for importing picklists without creating plates first
|
||||
//!
|
||||
//! Before the auto module, it was necessary for a user to create the plates
|
||||
//! used in an imported transfer before import.
|
||||
|
||||
use super::{string_well_to_pt, TransferRecord, read_csv};
|
||||
use crate::plate::{PlateFormat, PlateType};
|
||||
use crate::plate_instances::PlateInstance;
|
||||
|
@ -12,6 +17,7 @@ pub struct AutoOutput {
|
|||
pub transfers: Vec<Transfer>,
|
||||
}
|
||||
|
||||
/// Two lists of plates that are guaranteed to be unique (no duplicate plates)
|
||||
struct UniquePlates {
|
||||
sources: Vec<PlateInstance>,
|
||||
destinations: Vec<PlateInstance>,
|
||||
|
@ -24,6 +30,12 @@ const W384_ROW_MAX: u8 = 16;
|
|||
const W1536_COL_MAX: u8 = 48;
|
||||
const W1536_ROW_MAX: u8 = 32;
|
||||
|
||||
/// Main function for the auto module
|
||||
/// Takes a list of pre-deserialized transfer records and generates output
|
||||
/// This output is 3 lists of:
|
||||
/// 1. The source plates used in the picklist
|
||||
/// 2. The destination plates used in the picklist
|
||||
/// 3. All of the transfers between those plates
|
||||
pub fn auto(records: &[TransferRecord]) -> AutoOutput {
|
||||
let unique_plates = find_unique_plates(records);
|
||||
let transfers = get_transfer_for_all_pairs(records, &unique_plates);
|
||||
|
@ -31,11 +43,18 @@ pub fn auto(records: &[TransferRecord]) -> AutoOutput {
|
|||
AutoOutput { sources: unique_plates.sources, destinations: unique_plates.destinations, transfers }
|
||||
}
|
||||
|
||||
/// Helper function that reads a CSV and immediately dumps the resulting transfer records
|
||||
/// into the auto function defined in this module.
|
||||
pub fn read_csv_auto(data: &str) -> AutoOutput {
|
||||
let transfer_records = read_csv(data);
|
||||
auto(&transfer_records)
|
||||
}
|
||||
|
||||
/// Looks through a list of transfer records and generates two lists
|
||||
/// of all of the unique plates found in those transfers.
|
||||
/// Worth noting that the Transfer struct requires two associated PlateInstances;
|
||||
/// these PlateInstance structs are generated here---they are not present in a TransferRecord.
|
||||
/// See notes on the UniquePlates struct
|
||||
fn find_unique_plates(records: &[TransferRecord]) -> UniquePlates {
|
||||
let mut source_names: HashSet<&str> = HashSet::new();
|
||||
let mut destination_names: HashSet<&str> = HashSet::new();
|
||||
|
@ -79,6 +98,12 @@ fn find_unique_plates(records: &[TransferRecord]) -> UniquePlates {
|
|||
}
|
||||
}
|
||||
|
||||
/// Tries to guess the format of a plate given the southeastern-est well used.
|
||||
/// A picklist does not necessarily contain plate format info; this method guesses
|
||||
/// based on the well furthest from A1 that exists in a transfer.
|
||||
/// It's possible for a 1536 well plate to be seen as a 384 well if all of the wells
|
||||
/// used could have fit in the top-left quadrant of a 384 well plate
|
||||
/// (i.e. all lower than P24 in this case)
|
||||
fn guess_plate_size(plate_filtered_records: &[&TransferRecord], which: PlateType) -> PlateFormat {
|
||||
let mut guess = PlateFormat::W96; // Never guess smaller than 96
|
||||
for record in plate_filtered_records {
|
||||
|
@ -116,6 +141,17 @@ fn get_transfer_for_all_pairs(
|
|||
transfers
|
||||
}
|
||||
|
||||
/// Given a source and destination plate, get all of the wells transferred
|
||||
/// from source to destination and turn this into a Transfer.
|
||||
///
|
||||
/// Note that even if you have what looks like two separate transfers,
|
||||
/// this will join all transfers for a given source-dest pair.
|
||||
/// For example:
|
||||
/// Consider expanding all of src:A1 to the column dst:A
|
||||
/// and src:B1 -> row dst:1
|
||||
/// If you were making this transfer in plate tool, it would be easiest
|
||||
/// to do this as two separate transfers.
|
||||
/// On import, this would be seen as one transfer.
|
||||
fn get_transfer_for_pair(
|
||||
records: &[TransferRecord],
|
||||
source: &PlateInstance,
|
||||
|
|
|
@ -52,9 +52,12 @@ pub fn records_to_echo_client_csv(trs: Vec<TransferRecord>) -> Result<String, Bo
|
|||
Ok(data)
|
||||
}
|
||||
|
||||
/// Converts "spreadsheet format" well identification to coordinates
|
||||
pub fn string_well_to_pt(input: &str) -> Option<(u8, u8)> {
|
||||
lazy_static! {
|
||||
static ref REGEX: Regex = Regex::new(r"([A-Z,a-z]+)(\d+)").unwrap();
|
||||
|
||||
// Can this be removed?
|
||||
static ref REGEX_ALT: Regex = Regex::new(r"(\d+)").unwrap();
|
||||
}
|
||||
if let Some(c1) = REGEX.captures(input) {
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
//! This contains the `mangle_headers` function and its helpers
|
||||
//!
|
||||
//! Mangling headers is necessary to normalize CSV column names before
|
||||
//! deserialization can be done by Serde.
|
||||
//! Field detection occurs in `detect_field`.
|
||||
//!
|
||||
//! As of lib 0.4.0, unrecognized headers are ignored and left untouched by mangling.
|
||||
//! However, they are not passed through to any subsequent exports from plate-tool.
|
||||
|
||||
pub fn mangle_headers(data: &str) -> String {
|
||||
let (header, rows) = data.split_at(data.find('\n').unwrap());
|
||||
let fields = header.trim().split(",");
|
||||
|
|
|
@ -2,6 +2,10 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::{plate::PlateFormat, transfer::Transfer, util::num_to_letters};
|
||||
|
||||
/// Represents a single line of a CSV picklist.
|
||||
/// In practice, this is generated from the deserialize intermediate.
|
||||
/// A list of `TransferRecord`s can be used to create a `transfer::Transfer` struct;
|
||||
/// see the `auto` module for this.
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct TransferRecord {
|
||||
#[serde(rename = "Source Barcode")]
|
||||
|
@ -18,6 +22,12 @@ pub struct TransferRecord {
|
|||
pub concentration: Option<f32>,
|
||||
}
|
||||
|
||||
/// The deserialization intermediate is generated from a mangled CSV s.t.
|
||||
/// the column headers are standardized to those given to the derive macro.
|
||||
///
|
||||
/// `TransferRecord` can *always* be generated from the intermediate.
|
||||
/// Currently there's no reason why the inverse couldn't be true,
|
||||
/// but there's no reason to convert back into the deserialize-only intermediate.
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct TransferRecordDeserializeIntermediate {
|
||||
#[serde(rename = "sourceplate")]
|
||||
|
@ -78,6 +88,7 @@ impl From<TransferRecordDeserializeIntermediate> for TransferRecord {
|
|||
}
|
||||
|
||||
impl TransferRecordDeserializeIntermediate {
|
||||
/// Used to cull malformed picklist entries that lack required information
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.source_plate.is_empty()
|
||||
|| self.destination_plate.is_empty()
|
||||
|
@ -95,6 +106,7 @@ fn numeric_well_to_alphanumeric(input: u16, pformat: PlateFormat) -> Option<Stri
|
|||
Some(format!("{}{}", row_str, column))
|
||||
}
|
||||
|
||||
// Why is this here?
|
||||
pub fn volume_default() -> f32 {
|
||||
Transfer::default().volume
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue