@@ -73,6 +73,8 @@ impl PyTableProvider {
7373 }
7474}
7575const 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