Skip to content

Commit d32584d

Browse files
committed
Add option to only display a portion of a cell data and the user can click on a button to toggle showing more or less
1 parent 75dcc45 commit d32584d

File tree

1 file changed

+76
-4
lines changed

1 file changed

+76
-4
lines changed

src/dataframe.rs

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ use crate::{
5353
};
5454

5555
const MAX_TABLE_BYTES_TO_DISPLAY: usize = 2 * 1024 * 1024; // 2 MB
56+
const MIN_TABLE_ROWS_TO_DISPLAY: usize = 20;
57+
const MAX_LENGTH_CELL_WITHOUT_MINIMIZE: usize = 25;
5658

5759
/// A PyDataFrame is a representation of a logical plan and an API to compose statements.
5860
/// Use it to build a plan and `.collect()` to execute the plan and collect the result.
@@ -110,7 +112,37 @@ impl PyDataFrame {
110112
return Ok("No data to display".to_string());
111113
};
112114

115+
let table_uuid = uuid::Uuid::new_v4().to_string();
116+
113117
let mut html_str = "
118+
<style>
119+
.expandable-container {
120+
display: inline-block;
121+
max-width: 200px;
122+
}
123+
.expandable {
124+
white-space: nowrap;
125+
overflow: hidden;
126+
text-overflow: ellipsis;
127+
display: block;
128+
}
129+
.full-text {
130+
display: none;
131+
white-space: normal;
132+
}
133+
.expand-btn {
134+
cursor: pointer;
135+
color: blue;
136+
text-decoration: underline;
137+
border: none;
138+
background: none;
139+
font-size: inherit;
140+
display: block;
141+
margin-top: 5px;
142+
}
143+
</style>
144+
145+
114146
<div style=\"width: 100%; max-width: 1000px; max-height: 300px; overflow: auto; border: 1px solid #ccc;\">
115147
<table style=\"border-collapse: collapse; min-width: 100%\">
116148
<thead>\n".to_string();
@@ -134,24 +166,64 @@ impl PyDataFrame {
134166
let batch_size = batch.get_array_memory_size();
135167
let num_rows_to_display = match batch_size > MAX_TABLE_BYTES_TO_DISPLAY {
136168
true => {
137-
has_more = true;
169+
let num_batch_rows = batch.num_rows();
138170
let ratio = MAX_TABLE_BYTES_TO_DISPLAY as f32 / batch_size as f32;
139-
(batch.num_rows() as f32 * ratio).round() as usize
171+
let mut reduced_row_num = (num_batch_rows as f32 * ratio).round() as usize;
172+
if reduced_row_num < MIN_TABLE_ROWS_TO_DISPLAY {
173+
reduced_row_num = MIN_TABLE_ROWS_TO_DISPLAY.min(num_batch_rows);
174+
}
175+
176+
has_more = has_more || reduced_row_num < num_batch_rows;
177+
reduced_row_num
140178
}
141179
false => batch.num_rows(),
142180
};
143181

144182
for row in 0..num_rows_to_display {
145183
let mut cells = Vec::new();
146-
for formatter in &formatters {
147-
cells.push(format!("<td style='border: 1px solid black; padding: 8px; text-align: left; white-space: nowrap;'>{}</td>", formatter.value(row)));
184+
for (col, formatter) in formatters.iter().enumerate() {
185+
let cell_data = formatter.value(row).to_string();
186+
// From testing, primitive data types do not typically get larger than 21 characters
187+
if cell_data.len() > MAX_LENGTH_CELL_WITHOUT_MINIMIZE {
188+
let short_cell_data = &cell_data[0..MAX_LENGTH_CELL_WITHOUT_MINIMIZE];
189+
cells.push(format!("
190+
<td style='border: 1px solid black; padding: 8px; text-align: left; white-space: nowrap;'>
191+
<div class=\"expandable-container\">
192+
<span class=\"expandable\" id=\"{table_uuid}-min-text-{row}-{col}\">{short_cell_data}</span>
193+
<span class=\"full-text\" id=\"{table_uuid}-full-text-{row}-{col}\">{cell_data}</span>
194+
<button class=\"expand-btn\" onclick=\"toggleDataFrameCellText('{table_uuid}',{row},{col})\">...</button>
195+
</div>
196+
</td>"));
197+
} else {
198+
cells.push(format!("<td style='border: 1px solid black; padding: 8px; text-align: left; white-space: nowrap;'>{}</td>", formatter.value(row)));
199+
}
148200
}
149201
let row_str = cells.join("");
150202
html_str.push_str(&format!("<tr>{}</tr>\n", row_str));
151203
}
152204

153205
html_str.push_str("</tbody></table></div>\n");
154206

207+
html_str.push_str("
208+
<script>
209+
function toggleDataFrameCellText(table_uuid, row, col) {
210+
var shortText = document.getElementById(table_uuid + \"-min-text-\" + row + \"-\" + col);
211+
var fullText = document.getElementById(table_uuid + \"-full-text-\" + row + \"-\" + col);
212+
var button = event.target;
213+
214+
if (fullText.style.display === \"none\") {
215+
shortText.style.display = \"none\";
216+
fullText.style.display = \"inline\";
217+
button.textContent = \"(less)\";
218+
} else {
219+
shortText.style.display = \"inline\";
220+
fullText.style.display = \"none\";
221+
button.textContent = \"...\";
222+
}
223+
}
224+
</script>
225+
");
226+
155227
if has_more {
156228
html_str.push_str("Data truncated due to size.");
157229
}

0 commit comments

Comments
 (0)