Skip to content

Commit 46285fb

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 893c092 commit 46285fb

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
@@ -73,6 +73,8 @@ impl PyTableProvider {
7373
}
7474
}
7575
const MAX_TABLE_BYTES_TO_DISPLAY: usize = 2 * 1024 * 1024; // 2 MB
76+
const MIN_TABLE_ROWS_TO_DISPLAY: usize = 20;
77+
const MAX_LENGTH_CELL_WITHOUT_MINIMIZE: usize = 25;
7678

7779
/// A PyDataFrame is a representation of a logical plan and an API to compose statements.
7880
/// Use it to build a plan and `.collect()` to execute the plan and collect the result.
@@ -130,7 +132,37 @@ impl PyDataFrame {
130132
return Ok("No data to display".to_string());
131133
};
132134

135+
let table_uuid = uuid::Uuid::new_v4().to_string();
136+
133137
let mut html_str = "
138+
<style>
139+
.expandable-container {
140+
display: inline-block;
141+
max-width: 200px;
142+
}
143+
.expandable {
144+
white-space: nowrap;
145+
overflow: hidden;
146+
text-overflow: ellipsis;
147+
display: block;
148+
}
149+
.full-text {
150+
display: none;
151+
white-space: normal;
152+
}
153+
.expand-btn {
154+
cursor: pointer;
155+
color: blue;
156+
text-decoration: underline;
157+
border: none;
158+
background: none;
159+
font-size: inherit;
160+
display: block;
161+
margin-top: 5px;
162+
}
163+
</style>
164+
165+
134166
<div style=\"width: 100%; max-width: 1000px; max-height: 300px; overflow: auto; border: 1px solid #ccc;\">
135167
<table style=\"border-collapse: collapse; min-width: 100%\">
136168
<thead>\n".to_string();
@@ -154,24 +186,64 @@ impl PyDataFrame {
154186
let batch_size = batch.get_array_memory_size();
155187
let num_rows_to_display = match batch_size > MAX_TABLE_BYTES_TO_DISPLAY {
156188
true => {
157-
has_more = true;
189+
let num_batch_rows = batch.num_rows();
158190
let ratio = MAX_TABLE_BYTES_TO_DISPLAY as f32 / batch_size as f32;
159-
(batch.num_rows() as f32 * ratio).round() as usize
191+
let mut reduced_row_num = (num_batch_rows as f32 * ratio).round() as usize;
192+
if reduced_row_num < MIN_TABLE_ROWS_TO_DISPLAY {
193+
reduced_row_num = MIN_TABLE_ROWS_TO_DISPLAY.min(num_batch_rows);
194+
}
195+
196+
has_more = has_more || reduced_row_num < num_batch_rows;
197+
reduced_row_num
160198
}
161199
false => batch.num_rows(),
162200
};
163201

164202
for row in 0..num_rows_to_display {
165203
let mut cells = Vec::new();
166-
for formatter in &formatters {
167-
cells.push(format!("<td style='border: 1px solid black; padding: 8px; text-align: left; white-space: nowrap;'>{}</td>", formatter.value(row)));
204+
for (col, formatter) in formatters.iter().enumerate() {
205+
let cell_data = formatter.value(row).to_string();
206+
// From testing, primitive data types do not typically get larger than 21 characters
207+
if cell_data.len() > MAX_LENGTH_CELL_WITHOUT_MINIMIZE {
208+
let short_cell_data = &cell_data[0..MAX_LENGTH_CELL_WITHOUT_MINIMIZE];
209+
cells.push(format!("
210+
<td style='border: 1px solid black; padding: 8px; text-align: left; white-space: nowrap;'>
211+
<div class=\"expandable-container\">
212+
<span class=\"expandable\" id=\"{table_uuid}-min-text-{row}-{col}\">{short_cell_data}</span>
213+
<span class=\"full-text\" id=\"{table_uuid}-full-text-{row}-{col}\">{cell_data}</span>
214+
<button class=\"expand-btn\" onclick=\"toggleDataFrameCellText('{table_uuid}',{row},{col})\">...</button>
215+
</div>
216+
</td>"));
217+
} else {
218+
cells.push(format!("<td style='border: 1px solid black; padding: 8px; text-align: left; white-space: nowrap;'>{}</td>", formatter.value(row)));
219+
}
168220
}
169221
let row_str = cells.join("");
170222
html_str.push_str(&format!("<tr>{}</tr>\n", row_str));
171223
}
172224

173225
html_str.push_str("</tbody></table></div>\n");
174226

227+
html_str.push_str("
228+
<script>
229+
function toggleDataFrameCellText(table_uuid, row, col) {
230+
var shortText = document.getElementById(table_uuid + \"-min-text-\" + row + \"-\" + col);
231+
var fullText = document.getElementById(table_uuid + \"-full-text-\" + row + \"-\" + col);
232+
var button = event.target;
233+
234+
if (fullText.style.display === \"none\") {
235+
shortText.style.display = \"none\";
236+
fullText.style.display = \"inline\";
237+
button.textContent = \"(less)\";
238+
} else {
239+
shortText.style.display = \"inline\";
240+
fullText.style.display = \"none\";
241+
button.textContent = \"...\";
242+
}
243+
}
244+
</script>
245+
");
246+
175247
if has_more {
176248
html_str.push_str("Data truncated due to size.");
177249
}

0 commit comments

Comments
 (0)