Skip to content

Instantly share code, notes, and snippets.

@alekrutkowski
Last active November 20, 2024 15:59
Show Gist options
  • Save alekrutkowski/0c04558f8163ad403069ad8ea3a43bf6 to your computer and use it in GitHub Desktop.
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
// 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