// rust/01-data-loading.rs/*Data loading and processing patterns*/usestd::collections::HashMap;usestd::fs::File;usestd::io::{BufRead,BufReader};useserde::{Deserialize,Serialize};usethiserror::Error;/// Data loading error types.#[derive(Error, Debug)]pubenumDataLoadingError{#[error("File not found: {0}")]FileNotFound(String),#[error("Invalid CSV format: {0}")]InvalidCsv(String),#[error("Parsing error: {0}")]ParsingError(String),#[error("IO error: {0}")]IoError(#[from]std::io::Error),}/// Data record structure.#[derive(Debug, Clone, Serialize, Deserialize)]pubstructDataRecord{pubid:String,pubtimestamp:chrono::DateTime<chrono::Utc>,pubvalues:HashMap<String,f64>,pubmetadata:HashMap<String,String>,}/// CSV data loader.pubstructCsvDataLoader{file_path:String,delimiter:char,has_header:bool,}implCsvDataLoader{pubfnnew(file_path:String,delimiter:char,has_header:bool)->Self{Self{file_path,delimiter,has_header,}}/// Load data from CSV file.pubasyncfnload_data(&self)->Result<Vec<DataRecord>,DataLoadingError>{letfile=File::open(&self.file_path).map_err(|_|DataLoadingError::FileNotFound(self.file_path.clone()))?;letreader=BufReader::new(file);letmutlines=reader.lines();// Skip header if presentifself.has_header{lines.next();}letmutrecords=Vec::new();letmutrecord_id=0;forlineinlines{letline=line.map_err(DataLoadingError::IoError)?;letrecord=self.parse_line(&line,record_id)?;records.push(record);record_id+=1;}Ok(records)}/// Parse a single line of CSV data.fnparse_line(&self,line:&str,record_id:usize)->Result<DataRecord,DataLoadingError>{letfields:Vec<&str>=line.split(self.delimiter).collect();iffields.len()<3{returnErr(DataLoadingError::InvalidCsv(format!("Expected at least 3 fields, got {}",fields.len())));}letmutvalues=HashMap::new();letmutmetadata=HashMap::new();// Parse timestamp (assuming first field is timestamp)lettimestamp=chrono::DateTime::parse_from_rfc3339(fields[0]).map_err(|e|DataLoadingError::ParsingError(format!("Invalid timestamp: {}",e)))?.with_timezone(&chrono::Utc);// Parse numeric valuesfor(i,field)infields.iter().enumerate().skip(1){ifletOk(value)=field.parse::<f64>(){values.insert(format!("field_{}",i),value);}else{metadata.insert(format!("field_{}",i),field.to_string());}}Ok(DataRecord{id:format!("record_{}",record_id),timestamp,values,metadata,})}}/// Data aggregator for analysis.pubstructDataAggregator{data:Vec<DataRecord>,statistics:HashMap<String,StatisticalSummary>,}#[derive(Debug, Clone, Serialize, Deserialize)]pubstructStatisticalSummary{pubcount:usize,pubmean:f64,pubmedian:f64,pubstd_dev:f64,pubmin:f64,pubmax:f64,pubquartiles:(f64,f64,f64),// Q1, Q2, Q3}implDataAggregator{pubfnnew(data:Vec<DataRecord>)->Self{Self{data,statistics:HashMap::new(),}}/// Calculate statistics for all numeric fields.pubasyncfncalculate_statistics(&mutself)->Result<(),String>{ifself.data.is_empty(){returnErr("No data to analyze".to_string());}// Get all numeric field namesletfield_names:Vec<String>=self.data[0].values.keys().cloned().collect();// Calculate statistics for each fieldforfield_nameinfield_names{letvalues:Vec<f64>=self.data.iter().filter_map(|record|record.values.get(&field_name)).cloned().collect();if!values.is_empty(){letsummary=self.calculate_field_statistics(&values);self.statistics.insert(field_name,summary);}}Ok(())}/// Calculate statistics for a specific field.fncalculate_field_statistics(&self,values:&[f64])->StatisticalSummary{letmutsorted_values=values.to_vec();sorted_values.sort_by(|a,b|a.partial_cmp(b).unwrap());letcount=values.len();letsum:f64=values.iter().sum();letmean=sum/countasf64;letmedian=ifcount%2==0{(sorted_values[count/2-1]+sorted_values[count/2])/2.0}else{sorted_values[count/2]};letvariance:f64=values.iter().map(|x|(x-mean).powi(2)).sum::<f64>()/countasf64;letstd_dev=variance.sqrt();letmin=sorted_values[0];letmax=sorted_values[count-1];letq1=ifcount>=4{sorted_values[count/4]}else{min};letq3=ifcount>=4{sorted_values[3*count/4]}else{max};StatisticalSummary{count,mean,median,std_dev,min,max,quartiles:(q1,median,q3),}}/// Get statistics for a specific field.pubfnget_field_statistics(&self,field_name:&str)->Option<&StatisticalSummary>{self.statistics.get(field_name)}/// Get all statistics.pubfnget_all_statistics(&self)->&HashMap<String,StatisticalSummary>{&self.statistics}}#[cfg(test)]modtests{usesuper::*;#[tokio::test]asyncfntest_data_aggregator(){letmutdata=Vec::new();foriin0..10{letmutvalues=HashMap::new();values.insert("temperature".to_string(),20.0+iasf64);values.insert("pressure".to_string(),101325.0+iasf64*1000.0);letrecord=DataRecord{id:format!("record_{}",i),timestamp:chrono::Utc::now(),values,metadata:HashMap::new(),};data.push(record);}letmutaggregator=DataAggregator::new(data);aggregator.calculate_statistics().await.unwrap();letstats=aggregator.get_field_statistics("temperature");assert!(stats.is_some());assert_eq!(stats.unwrap().count,10);}}
// rust/03-data-visualization.rs/*Data visualization patterns and best practices*/usestd::collections::HashMap;useserde::{Deserialize,Serialize};/// Data visualization service.pubstructDataVisualizationService{data:Vec<DataPoint>,charts:Vec<Chart>,}#[derive(Debug, Clone, Serialize, Deserialize)]pubstructDataPoint{pubx:f64,puby:f64,publabel:Option<String>,pubcolor:Option<String>,}#[derive(Debug, Clone, Serialize, Deserialize)]pubstructChart{pubid:String,pubtitle:String,pubchart_type:ChartType,pubdata:Vec<DataPoint>,pubx_label:String,puby_label:String,pubwidth:u32,pubheight:u32,}#[derive(Debug, Clone, Serialize, Deserialize)]pubenumChartType{Line,Bar,Scatter,Histogram,BoxPlot,}implDataVisualizationService{pubfnnew()->Self{Self{data:Vec::new(),charts:Vec::new(),}}/// Add data points.pubfnadd_data(&mutself,data:Vec<DataPoint>){self.data.extend(data);}/// Create a line chart.pubfncreate_line_chart(&mutself,id:String,title:String,data:Vec<DataPoint>)->Result<(),String>{ifdata.is_empty(){returnErr("Cannot create chart with empty data".to_string());}letchart=Chart{id,title,chart_type:ChartType::Line,data,x_label:"X Axis".to_string(),y_label:"Y Axis".to_string(),width:800,height:600,};self.charts.push(chart);Ok(())}/// Create a bar chart.pubfncreate_bar_chart(&mutself,id:String,title:String,data:Vec<DataPoint>)->Result<(),String>{ifdata.is_empty(){returnErr("Cannot create chart with empty data".to_string());}letchart=Chart{id,title,chart_type:ChartType::Bar,data,x_label:"Categories".to_string(),y_label:"Values".to_string(),width:800,height:600,};self.charts.push(chart);Ok(())}/// Create a scatter plot.pubfncreate_scatter_plot(&mutself,id:String,title:String,data:Vec<DataPoint>)->Result<(),String>{ifdata.is_empty(){returnErr("Cannot create chart with empty data".to_string());}letchart=Chart{id,title,chart_type:ChartType::Scatter,data,x_label:"X Values".to_string(),y_label:"Y Values".to_string(),width:800,height:600,};self.charts.push(chart);Ok(())}/// Create a histogram.pubfncreate_histogram(&mutself,id:String,title:String,data:Vec<f64>,bins:usize)->Result<(),String>{ifdata.is_empty(){returnErr("Cannot create histogram with empty data".to_string());}lethistogram_data=self.create_histogram_data(data,bins);letchart=Chart{id,title,chart_type:ChartType::Histogram,data:histogram_data,x_label:"Values".to_string(),y_label:"Frequency".to_string(),width:800,height:600,};self.charts.push(chart);Ok(())}/// Create histogram data.fncreate_histogram_data(&self,data:Vec<f64>,bins:usize)->Vec<DataPoint>{letmin=data.iter().cloned().fold(f64::INFINITY,f64::min);letmax=data.iter().cloned().fold(f64::NEG_INFINITY,f64::max);letbin_width=(max-min)/binsasf64;letmuthistogram=vec![0;bins];forvalueindata{letbin_index=((value-min)/bin_width)asusize;letbin_index=bin_index.min(bins-1);histogram[bin_index]+=1;}letmuthistogram_data=Vec::new();for(i,count)inhistogram.iter().enumerate(){letx=min+(iasf64+0.5)*bin_width;histogram_data.push(DataPoint{x,y:*countasf64,label:None,color:None,});}histogram_data}/// Get all charts.pubfnget_charts(&self)->&[Chart]{&self.charts}/// Get a specific chart.pubfnget_chart(&self,id:&str)->Option<&Chart>{self.charts.iter().find(|chart|chart.id==id)}/// Export chart data as JSON.pubfnexport_chart_json(&self,id:&str)->Result<String,String>{letchart=self.get_chart(id).ok_or_else(||"Chart not found".to_string())?;serde_json::to_string_pretty(chart).map_err(|e|format!("Failed to serialize chart: {}",e))}/// Export all charts as JSON.pubfnexport_all_charts_json(&self)->Result<String,String>{serde_json::to_string_pretty(&self.charts).map_err(|e|format!("Failed to serialize charts: {}",e))}}/// Data analysis report generator.pubstructDataAnalysisReport{title:String,sections:Vec<ReportSection>,}#[derive(Debug, Clone, Serialize, Deserialize)]pubstructReportSection{pubtitle:String,pubcontent:String,pubcharts:Vec<String>,// Chart IDs}implDataAnalysisReport{pubfnnew(title:String)->Self{Self{title,sections:Vec::new(),}}/// Add a section to the report.pubfnadd_section(&mutself,title:String,content:String,charts:Vec<String>){self.sections.push(ReportSection{title,content,charts,});}/// Generate HTML report.pubfngenerate_html(&self)->String{letmuthtml=String::new();html.push_str(&format!("<html><head><title>{}</title></head><body>",self.title));html.push_str(&format!("<h1>{}</h1>",self.title));forsectionin&self.sections{html.push_str(&format!("<h2>{}</h2>",section.title));html.push_str(&format!("<p>{}</p>",section.content));if!section.charts.is_empty(){html.push_str("<div class=\"charts\">");forchart_idin§ion.charts{html.push_str(&format!("<div class=\"chart\" id=\"{}\"></div>",chart_id));}html.push_str("</div>");}}html.push_str("</body></html>");html}/// Generate Markdown report.pubfngenerate_markdown(&self)->String{letmutmarkdown=String::new();markdown.push_str(&format!("# {}\n\n",self.title));forsectionin&self.sections{markdown.push_str(&format!("## {}\n\n",section.title));markdown.push_str(&format!("{}\n\n",section.content));if!section.charts.is_empty(){markdown.push_str("### Charts\n\n");forchart_idin§ion.charts{markdown.push_str(&format!("- Chart: {}\n",chart_id));}markdown.push_str("\n");}}markdown}}#[cfg(test)]modtests{usesuper::*;#[test]fntest_data_visualization_service(){letmutservice=DataVisualizationService::new();letdata=vec![DataPoint{x:1.0,y:2.0,label:None,color:None},DataPoint{x:2.0,y:4.0,label:None,color:None},DataPoint{x:3.0,y:6.0,label:None,color:None},];service.create_line_chart("chart1".to_string(),"Test Chart".to_string(),data).unwrap();assert_eq!(service.get_charts().len(),1);}#[test]fntest_data_analysis_report(){letmutreport=DataAnalysisReport::new("Test Report".to_string());report.add_section("Introduction".to_string(),"This is a test report.".to_string(),vec!["chart1".to_string()],);lethtml=report.generate_html();assert!(html.contains("Test Report"));assert!(html.contains("Introduction"));}}
// 1. Data loadingletloader=CsvDataLoader::new("data.csv".to_string(),',',true);letdata=loader.load_data().await?;// 2. Statistical analysisletmutanalyzer=StatisticalAnalyzer::new(values);letstats=analyzer.calculate_statistics()?;// 3. Data visualizationletmutservice=DataVisualizationService::new();service.create_line_chart("chart1".to_string(),"Title".to_string(),data)?;