Last active
November 20, 2024 15:59
-
-
Save alekrutkowski/0c04558f8163ad403069ad8ea3a43bf6 to your computer and use it in GitHub Desktop.
Rust extendr/rextendr code to take R's data.frame and a file path as inputs, and save the data.frame in an Excel file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Conversion of missing values doesn't work!!! -- to be corrected | |
use extendr_api::prelude::*; | |
use umya_spreadsheet::*; | |
use umya_spreadsheet::writer::xlsx; | |
#[extendr] | |
fn save_dataframe_to_excel(df: Robj, file_path: &str) -> extendr_api::Result<()> { | |
// Ensure the input is a DataFrame | |
let dataframe = df | |
.as_list() | |
.ok_or_else(|| extendr_api::error::Error::Other("Input is not a valid R DataFrame".to_string()))?; | |
// Get column names | |
let colnames = dataframe.names().ok_or_else(|| extendr_api::error::Error::Other("DataFrame has no column names".to_string()))?; | |
// Create a new Excel workbook and get the active sheet | |
let mut workbook = umya_spreadsheet::new_file(); | |
let sheet = workbook.get_active_sheet_mut(); | |
// Write column names to the first row of the Excel sheet | |
for (col_index, colname) in colnames.into_iter().enumerate() { | |
sheet.get_cell_mut((col_index as u32 + 1, 1)).set_value(colname); | |
} | |
// Write data to the Excel sheet | |
for (col_index, (_, col)) in dataframe.into_iter().enumerate() { | |
let col_data: Vec<String> = if let Some(vec) = col.as_real_vector() { | |
vec.iter().map(|&v| if v.is_nan() {"NA".to_string()} else {v.to_string()}).collect() // Handle f64 | |
} else if let Some(vec) = col.as_integer_vector() { | |
vec.iter().map(|&v| if v==-2147483648 {"NA".to_string()} else {v.to_string()}).collect() // Handle i32 | |
} else if let Some(vec) = col.as_str_vector() { | |
vec.iter().map(|&v| v.to_string()).collect() // Handle &str | |
} else if let Some(vec) = col.as_logical_vector() { | |
vec.iter() | |
.map(|v| { | |
if v.is_true() { | |
"TRUE".to_string() | |
} else if v.is_false() { | |
"FALSE".to_string() | |
} else { | |
"NA".to_string() // Handle NA | |
} | |
}) | |
.collect() | |
} else { | |
return Err(extendr_api::error::Error::Other( | |
"Unsupported column type in DataFrame".to_string(), | |
)); | |
}; | |
for (row_index, cell_value) in col_data.into_iter().enumerate() { | |
sheet | |
.get_cell_mut((col_index as u32 + 1, row_index as u32 + 2)) | |
.set_value(cell_value); | |
} | |
} | |
// Save the workbook to the specified file path | |
xlsx::write(&workbook, file_path).map_err(|e| extendr_api::error::Error::Other(format!("Failed to write Excel file: {:?}", e)))?; | |
Ok(()) | |
} | |
extendr_module! { | |
mod mymodule; | |
fn save_dataframe_to_excel; | |
} | |
// Note: Make sure to add `umya-spreadsheet` as a dependency in your `Cargo.toml`, like so: | |
// | |
// [dependencies] | |
// extendr-api = "0.7" | |
// umya-spreadsheet = "2.1" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment