dataframe-textual 2.9.1__py3-none-any.whl → 2.10.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -260,7 +260,7 @@ class DataFrameTable(DataTable):
260
260
  ("enter", "view_row_detail", "View row details"),
261
261
  ("F", "show_frequency", "Show frequency"),
262
262
  ("s", "show_statistics", "Show statistics for column"),
263
- ("S", "show_statistics('dataframe')", "Show statistics for dataframe"),
263
+ ("S", "show_statistics(-1)", "Show statistics for dataframe"),
264
264
  # Sort
265
265
  ("left_square_bracket", "sort_ascending", "Sort ascending"), # `[`
266
266
  ("right_square_bracket", "sort_descending", "Sort descending"), # `]`
@@ -747,13 +747,16 @@ class DataFrameTable(DataTable):
747
747
  """Show frequency distribution for the current column."""
748
748
  self.do_show_frequency()
749
749
 
750
- def action_show_statistics(self, scope: str = "column") -> None:
750
+ def action_show_statistics(self, cidx: int | None = None) -> None:
751
751
  """Show statistics for the current column or entire dataframe.
752
752
 
753
753
  Args:
754
- scope: Either "column" for current column stats or "dataframe" for all columns.
754
+ cidx: Column index
755
+ If -1, show statistics for entire dataframe.
756
+ If None, show statistics for current column, otherwise for specified column.
757
+
755
758
  """
756
- self.do_show_statistics(scope)
759
+ self.do_show_statistics(cidx)
757
760
 
758
761
  def action_metadata_shape(self) -> None:
759
762
  """Show metadata about the dataframe (row and column counts)."""
@@ -1661,26 +1664,26 @@ class DataFrameTable(DataTable):
1661
1664
  # Push the modal screen
1662
1665
  self.app.push_screen(RowDetailScreen(ridx, self))
1663
1666
 
1664
- def do_show_frequency(self) -> None:
1665
- """Show frequency distribution for the current column."""
1666
- cidx = self.cursor_col_idx
1667
+ def do_show_frequency(self, cidx=None) -> None:
1668
+ """Show frequency distribution for a given columnn."""
1669
+ cidx = cidx or self.cursor_col_idx
1667
1670
 
1668
1671
  # Push the frequency modal screen
1669
1672
  self.app.push_screen(FrequencyScreen(cidx, self))
1670
1673
 
1671
- def do_show_statistics(self, scope: str = "column") -> None:
1674
+ def do_show_statistics(self, cidx: int | None = None) -> None:
1672
1675
  """Show statistics for the current column or entire dataframe.
1673
1676
 
1674
1677
  Args:
1675
- scope: Either "column" for current column stats or "dataframe" for all columns.
1678
+ cidx: Column index to show statistics for. If None, show for entire dataframe.
1676
1679
  """
1677
- if scope == "dataframe":
1680
+ if cidx == -1:
1678
1681
  # Show statistics for entire dataframe
1679
- self.app.push_screen(StatisticsScreen(self, col_idx=None))
1682
+ self.app.push_screen(StatisticsScreen(self, cidx=None))
1680
1683
  else:
1681
- # Show statistics for current column
1682
- cidx = self.cursor_col_idx
1683
- self.app.push_screen(StatisticsScreen(self, col_idx=cidx))
1684
+ # Show statistics for current column or specified column
1685
+ cidx = self.cursor_col_idx if cidx is None else cidx
1686
+ self.app.push_screen(StatisticsScreen(self, cidx=cidx))
1684
1687
 
1685
1688
  def do_metadata_shape(self) -> None:
1686
1689
  """Show metadata about the dataframe (row and column counts)."""
@@ -102,7 +102,7 @@ class TableScreen(ModalScreen):
102
102
  if cidx_name_value is None:
103
103
  return
104
104
  cidx, col_name, col_value = cidx_name_value
105
- self.log(f"Filtering or viewing by `{col_name} == {col_value}`")
105
+ # self.log(f"Filtering or viewing by `{col_name} == {col_value}`")
106
106
 
107
107
  # Handle NULL values
108
108
  if col_value == NULL:
@@ -115,7 +115,7 @@ class TableScreen(ModalScreen):
115
115
  value_display = f"[$success]{col_value}[/]"
116
116
 
117
117
  df_filtered = self.dftable.df.lazy().filter(expr).collect()
118
- self.log(f"Filtered dataframe has {len(df_filtered)} rows")
118
+ # self.log(f"Filtered dataframe has {len(df_filtered)} rows")
119
119
 
120
120
  ok_rids = set(df_filtered[RID].to_list())
121
121
  if not ok_rids:
@@ -134,9 +134,45 @@ class TableScreen(ModalScreen):
134
134
  else:
135
135
  self.dftable.view_rows((expr, cidx, False, True))
136
136
 
137
- # Dismiss the frequency screen
137
+ # Dismiss the current modal screen
138
138
  self.app.pop_screen()
139
139
 
140
+ def show_frequency(self, cidx_name_value: tuple[int, str, Any] | None) -> None:
141
+ """Show frequency by the selected value.
142
+
143
+ Args:
144
+ col_name_value: Tuple of (column_name, column_value) to filter/view by, or None.
145
+ """
146
+ if cidx_name_value is None:
147
+ return
148
+ cidx, col_name, col_value = cidx_name_value
149
+ # self.log(f"Showing frequency for `{col_name} == {col_value}`")
150
+
151
+ # Do not dismiss the current modal screen so it can be returned to
152
+ # when frequency screen is closed.
153
+ # self.app.pop_screen()
154
+
155
+ # Show frequency screen
156
+ self.dftable.do_show_frequency(cidx)
157
+
158
+ def show_statistics(self, cidx_name_value: tuple[int, str, Any] | None) -> None:
159
+ """Show frequency by the selected value.
160
+
161
+ Args:
162
+ col_name_value: Tuple of (column_name, column_value) to filter/view by, or None.
163
+ """
164
+ if cidx_name_value is None:
165
+ return
166
+ cidx, col_name, col_value = cidx_name_value
167
+ # self.log(f"Showing statistics for `{col_name} == {col_value}`")
168
+
169
+ # Do not dismiss the current modal screen so it can be returned to
170
+ # when frequency screen is closed.
171
+ # self.app.pop_screen()
172
+
173
+ # Show statistics screen
174
+ self.dftable.do_show_statistics(cidx)
175
+
140
176
 
141
177
  class RowDetailScreen(TableScreen):
142
178
  """Modal screen to display a single row's details."""
@@ -175,10 +211,15 @@ class RowDetailScreen(TableScreen):
175
211
  self.table.cursor_type = "row"
176
212
 
177
213
  def on_key(self, event) -> None:
178
- """Handle key press events in the row detail screen.
214
+ """Handle key press events on the row detail screen.
179
215
 
180
- Supports 'v' for filtering and '"' for highlighting the main table
181
- by the value in the selected row.
216
+ Supported keys:
217
+ - 'v': View the main table by the selected value.
218
+ - '"': Filter the main table by the selected value.
219
+ - '{': Move to the previous row.
220
+ - '}': Move to the next row.
221
+ - 'F': Show frequency for the selected value.
222
+ - 's': Show statistics for the selected value.
182
223
 
183
224
  Args:
184
225
  event: The key event object.
@@ -207,8 +248,17 @@ class RowDetailScreen(TableScreen):
207
248
  self.dftable.move_cursor_to(self.ridx)
208
249
  self.build_table()
209
250
  event.stop()
251
+ elif event.key == "F":
252
+ # Show frequency for the selected value
253
+ self.show_frequency(self.get_cidx_name_value())
254
+ event.stop()
255
+ elif event.key == "s":
256
+ # Show statistics for the selected value
257
+ self.show_statistics(self.get_cidx_name_value())
258
+ event.stop()
210
259
 
211
260
  def get_cidx_name_value(self) -> tuple[int, str, Any] | None:
261
+ """Get the current column info."""
212
262
  cidx = self.table.cursor_row
213
263
  if cidx >= len(self.df.columns):
214
264
  return None # Invalid row
@@ -224,9 +274,9 @@ class StatisticsScreen(TableScreen):
224
274
 
225
275
  CSS = TableScreen.DEFAULT_CSS.replace("TableScreen", "StatisticsScreen")
226
276
 
227
- def __init__(self, dftable: "DataFrameTable", col_idx: int | None = None):
277
+ def __init__(self, dftable: "DataFrameTable", cidx: int | None = None):
228
278
  super().__init__(dftable)
229
- self.col_idx = col_idx # None for dataframe statistics, otherwise column index
279
+ self.cidx = cidx # None for dataframe statistics, otherwise column index
230
280
 
231
281
  def on_mount(self) -> None:
232
282
  """Create the statistics table."""
@@ -236,7 +286,7 @@ class StatisticsScreen(TableScreen):
236
286
  """Build the statistics table."""
237
287
  self.table.clear(columns=True)
238
288
 
239
- if self.col_idx is None:
289
+ if self.cidx is None:
240
290
  # Dataframe statistics
241
291
  self.build_dataframe_stats()
242
292
  self.table.cursor_type = "column"
@@ -247,7 +297,7 @@ class StatisticsScreen(TableScreen):
247
297
 
248
298
  def build_column_stats(self) -> None:
249
299
  """Build statistics for a single column."""
250
- col_name = self.df.columns[self.col_idx]
300
+ col_name = self.df.columns[self.cidx]
251
301
  lf = self.df.lazy()
252
302
 
253
303
  # Get column statistics
@@ -500,6 +550,25 @@ class MetaColumnScreen(TableScreen):
500
550
  """
501
551
  self.build_table()
502
552
 
553
+ def on_key(self, event) -> None:
554
+ """Handle key press events on the column metadata screen.
555
+
556
+ Supports keys:
557
+ - 'F': Show frequency for the selected value.
558
+ - 's': Show statistics for the selected value.
559
+
560
+ Args:
561
+ event: The key event object.
562
+ """
563
+ if event.key == "F":
564
+ # Show frequency for the selected value
565
+ self.show_frequency(self.get_cidx_name_value())
566
+ event.stop()
567
+ elif event.key == "s":
568
+ # Show statistics for the selected value
569
+ self.show_statistics(self.get_cidx_name_value())
570
+ event.stop()
571
+
503
572
  def build_table(self) -> None:
504
573
  """Build the column metadata table."""
505
574
  self.table.clear(columns=True)
@@ -524,4 +593,15 @@ class MetaColumnScreen(TableScreen):
524
593
  dc_str.format("Datetime" if str(col_type).startswith("Datetime") else col_type, style=dc.style),
525
594
  )
526
595
 
527
- self.table.cursor_type = "none"
596
+ self.table.cursor_type = "row"
597
+
598
+ def get_cidx_name_value(self) -> int | None:
599
+ """Get the current column info."""
600
+ cidx = self.table.cursor_row
601
+ if cidx >= len(self.df.columns):
602
+ return None # Invalid row
603
+
604
+ col_name = self.df.columns[cidx]
605
+ col_value = None
606
+
607
+ return cidx, col_name, col_value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataframe-textual
3
- Version: 2.9.1
3
+ Version: 2.10.1
4
4
  Summary: Interactive terminal viewer/editor for tabular data
5
5
  Project-URL: Homepage, https://github.com/need47/dataframe-textual
6
6
  Project-URL: Repository, https://github.com/need47/dataframe-textual.git
@@ -423,6 +423,8 @@ Useful for examining wide datasets where columns don't fit well on screen.
423
423
  - Press `"` to **filter** all rows containing the selected column value (others removed)
424
424
  - Press `{` to move to the previous row
425
425
  - Press `}` to move to the next row
426
+ - Press `F` to show the frequency table for the selected column
427
+ - Press `s` to show the statistics table for the selected column
426
428
  - Press `q` or `Escape` to close the modal
427
429
 
428
430
  ### 3. Row Selection
@@ -587,6 +589,10 @@ View quick metadata about your dataframe and columns to understand their structu
587
589
  - **Name** - Column name
588
590
  - **Type** - Data type (e.g., Int64, String, Float64, Boolean)
589
591
 
592
+ **In the Column Metadata Table**
593
+ - Press `F` to show the frequency table for the selected column
594
+ - Press `s` to show the statistics table for the selected column
595
+
590
596
  **In Metadata Modals**:
591
597
  - Press `q` or `Escape` to close
592
598
 
@@ -0,0 +1,14 @@
1
+ dataframe_textual/__init__.py,sha256=E53fW1spQRA4jW9grxSqPEmoe9zofzr6twdveMbt_W8,1310
2
+ dataframe_textual/__main__.py,sha256=tJ6FjjV25ZQzaMdqD5XcDVRZfj8l6kgGvXyrn975rjo,3999
3
+ dataframe_textual/common.py,sha256=CNRdHP3N1li2dy9OsTiW-zfpzf8zcrt2fW8mmYY-YVA,29073
4
+ dataframe_textual/data_frame_help_panel.py,sha256=UEtj64XsVRdtLzuwOaITfoEQUkAfwFuvpr5Npip5WHs,3381
5
+ dataframe_textual/data_frame_table.py,sha256=EAtUrzygpppdgEOk1FhSZWwDAwdKLpF-1s2iAE6EI3E,148529
6
+ dataframe_textual/data_frame_viewer.py,sha256=_VwbCcRBgdTcrZmgS2mRwIJ-cFxOeJ55twDFvQUHMfk,28723
7
+ dataframe_textual/sql_screen.py,sha256=P3j1Fv45NIKEYo9adb7NPod54FaU-djFIvCUMMHbvjY,7534
8
+ dataframe_textual/table_screen.py,sha256=aiMzI_kKiR2_3U1bqWHvaEkg4rqm62pXoMm_s1-19QU,21962
9
+ dataframe_textual/yes_no_screen.py,sha256=LC42DeJRIWb-PdpR3FDNvwxhnfZ6OXfU9Kxiu340BNE,26132
10
+ dataframe_textual-2.10.1.dist-info/METADATA,sha256=0-PLV-wlVMGd9a1rbM0SV5PCaHJ5L9D07wFpfNp4z6A,29825
11
+ dataframe_textual-2.10.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
12
+ dataframe_textual-2.10.1.dist-info/entry_points.txt,sha256=R_GoooOxcq6ab4RaHiVoZ4zrZJ-phMcGmlL2rwqncW8,107
13
+ dataframe_textual-2.10.1.dist-info/licenses/LICENSE,sha256=AVTg0gk1X-LHI-nnHlAMDQetrwuDZK4eypgSMDO46Yc,1069
14
+ dataframe_textual-2.10.1.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- dataframe_textual/__init__.py,sha256=E53fW1spQRA4jW9grxSqPEmoe9zofzr6twdveMbt_W8,1310
2
- dataframe_textual/__main__.py,sha256=tJ6FjjV25ZQzaMdqD5XcDVRZfj8l6kgGvXyrn975rjo,3999
3
- dataframe_textual/common.py,sha256=CNRdHP3N1li2dy9OsTiW-zfpzf8zcrt2fW8mmYY-YVA,29073
4
- dataframe_textual/data_frame_help_panel.py,sha256=UEtj64XsVRdtLzuwOaITfoEQUkAfwFuvpr5Npip5WHs,3381
5
- dataframe_textual/data_frame_table.py,sha256=PeLmedBpUvyw9ecVz15mITltb5gBMpsaPnX5PGHMpF0,148396
6
- dataframe_textual/data_frame_viewer.py,sha256=_VwbCcRBgdTcrZmgS2mRwIJ-cFxOeJ55twDFvQUHMfk,28723
7
- dataframe_textual/sql_screen.py,sha256=P3j1Fv45NIKEYo9adb7NPod54FaU-djFIvCUMMHbvjY,7534
8
- dataframe_textual/table_screen.py,sha256=XPzJI6FXjwnxtQSMTmluygwkYM-0-Lx3v9o-MuL6bMg,19071
9
- dataframe_textual/yes_no_screen.py,sha256=LC42DeJRIWb-PdpR3FDNvwxhnfZ6OXfU9Kxiu340BNE,26132
10
- dataframe_textual-2.9.1.dist-info/METADATA,sha256=zjWgudFlnKb817dcMQe5js7KBDj8yiT0fOqlBs0yoKk,29532
11
- dataframe_textual-2.9.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
12
- dataframe_textual-2.9.1.dist-info/entry_points.txt,sha256=R_GoooOxcq6ab4RaHiVoZ4zrZJ-phMcGmlL2rwqncW8,107
13
- dataframe_textual-2.9.1.dist-info/licenses/LICENSE,sha256=AVTg0gk1X-LHI-nnHlAMDQetrwuDZK4eypgSMDO46Yc,1069
14
- dataframe_textual-2.9.1.dist-info/RECORD,,