dataframe-textual 1.16.2__py3-none-any.whl → 2.0.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.
- dataframe_textual/__init__.py +27 -1
- dataframe_textual/__main__.py +7 -0
- dataframe_textual/common.py +15 -9
- dataframe_textual/data_frame_help_panel.py +0 -3
- dataframe_textual/data_frame_table.py +622 -559
- dataframe_textual/data_frame_viewer.py +16 -8
- dataframe_textual/sql_screen.py +8 -2
- dataframe_textual/table_screen.py +25 -51
- dataframe_textual/yes_no_screen.py +9 -18
- {dataframe_textual-1.16.2.dist-info → dataframe_textual-2.0.1.dist-info}/METADATA +10 -10
- dataframe_textual-2.0.1.dist-info/RECORD +14 -0
- dataframe_textual-1.16.2.dist-info/RECORD +0 -14
- {dataframe_textual-1.16.2.dist-info → dataframe_textual-2.0.1.dist-info}/WHEEL +0 -0
- {dataframe_textual-1.16.2.dist-info → dataframe_textual-2.0.1.dist-info}/entry_points.txt +0 -0
- {dataframe_textual-1.16.2.dist-info → dataframe_textual-2.0.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -248,12 +248,7 @@ class DataFrameViewer(App):
|
|
|
248
248
|
Opens the save dialog for the active tab's DataFrameTable to save its data.
|
|
249
249
|
"""
|
|
250
250
|
if table := self.get_active_table():
|
|
251
|
-
table.do_save_to_file(
|
|
252
|
-
|
|
253
|
-
def action_save_current_tab_overwrite(self) -> None:
|
|
254
|
-
"""Save the currently active tab to file, overwriting if it exists."""
|
|
255
|
-
if table := self.get_active_table():
|
|
256
|
-
table.save_to_file((table.filename, False, False))
|
|
251
|
+
table.do_save_to_file(all_tabs=False)
|
|
257
252
|
|
|
258
253
|
def action_save_all_tabs(self) -> None:
|
|
259
254
|
"""Save all open tabs to their respective files.
|
|
@@ -261,12 +256,25 @@ class DataFrameViewer(App):
|
|
|
261
256
|
Iterates through all DataFrameTable widgets and opens the save dialog for each.
|
|
262
257
|
"""
|
|
263
258
|
if table := self.get_active_table():
|
|
264
|
-
table.do_save_to_file(
|
|
259
|
+
table.do_save_to_file(all_tabs=True)
|
|
260
|
+
|
|
261
|
+
def action_save_current_tab_overwrite(self) -> None:
|
|
262
|
+
"""Save the currently active tab to file, overwriting if it exists."""
|
|
263
|
+
if table := self.get_active_table():
|
|
264
|
+
filepath = Path(table.filename)
|
|
265
|
+
filename = filepath.with_stem(table.tabname)
|
|
266
|
+
table.save_to_file((filename, False, False))
|
|
265
267
|
|
|
266
268
|
def action_save_all_tabs_overwrite(self) -> None:
|
|
267
269
|
"""Save all open tabs to their respective files, overwriting if they exist."""
|
|
268
270
|
if table := self.get_active_table():
|
|
269
|
-
|
|
271
|
+
filepath = Path(table.filename)
|
|
272
|
+
if filepath.suffix.lower() in [".xlsx", ".xls"]:
|
|
273
|
+
filename = table.filename
|
|
274
|
+
else:
|
|
275
|
+
filename = "all-tabs.xlsx"
|
|
276
|
+
|
|
277
|
+
table.save_to_file((filename, True, False))
|
|
270
278
|
|
|
271
279
|
def action_duplicate_tab(self) -> None:
|
|
272
280
|
"""Duplicate the currently active tab.
|
dataframe_textual/sql_screen.py
CHANGED
|
@@ -13,6 +13,8 @@ from textual.screen import ModalScreen
|
|
|
13
13
|
from textual.widgets import Button, Input, Label, SelectionList, TextArea
|
|
14
14
|
from textual.widgets.selection_list import Selection
|
|
15
15
|
|
|
16
|
+
from .common import RID
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
class SqlScreen(ModalScreen):
|
|
18
20
|
"""Base class for modal screens handling SQL query."""
|
|
@@ -164,7 +166,11 @@ class SimpleSqlScreen(SqlScreen):
|
|
|
164
166
|
container.border_title = "SQL Query"
|
|
165
167
|
yield Label("SELECT columns (all if none selected):", id="select-label")
|
|
166
168
|
yield SelectionList(
|
|
167
|
-
*[
|
|
169
|
+
*[
|
|
170
|
+
Selection(col, col)
|
|
171
|
+
for col in self.df.columns
|
|
172
|
+
if col not in self.dftable.hidden_columns and col != RID
|
|
173
|
+
],
|
|
168
174
|
id="column-selection",
|
|
169
175
|
)
|
|
170
176
|
yield Label("WHERE condition (optional)", id="where-label")
|
|
@@ -175,7 +181,7 @@ class SimpleSqlScreen(SqlScreen):
|
|
|
175
181
|
"""Handle Yes button/Enter key press."""
|
|
176
182
|
selections = self.query_one(SelectionList).selected
|
|
177
183
|
if not selections:
|
|
178
|
-
selections = [col for col in self.df.columns if col not in self.dftable.hidden_columns]
|
|
184
|
+
selections = [col for col in self.df.columns if col not in self.dftable.hidden_columns and col != RID]
|
|
179
185
|
|
|
180
186
|
columns = ", ".join(f"`{s}`" for s in selections)
|
|
181
187
|
where = self.query_one(Input).value.strip()
|
|
@@ -13,7 +13,7 @@ from textual.renderables.bar import Bar
|
|
|
13
13
|
from textual.screen import ModalScreen
|
|
14
14
|
from textual.widgets import DataTable
|
|
15
15
|
|
|
16
|
-
from .common import NULL, NULL_DISPLAY,
|
|
16
|
+
from .common import NULL, NULL_DISPLAY, RID, DtypeConfig, format_float
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class TableScreen(ModalScreen):
|
|
@@ -45,9 +45,6 @@ class TableScreen(ModalScreen):
|
|
|
45
45
|
|
|
46
46
|
Args:
|
|
47
47
|
dftable: Reference to the parent DataFrameTable widget.
|
|
48
|
-
|
|
49
|
-
Returns:
|
|
50
|
-
None
|
|
51
48
|
"""
|
|
52
49
|
super().__init__()
|
|
53
50
|
self.dftable = dftable # DataFrameTable
|
|
@@ -71,9 +68,6 @@ class TableScreen(ModalScreen):
|
|
|
71
68
|
|
|
72
69
|
Subclasses should implement this method to populate the DataTable
|
|
73
70
|
with appropriate columns and rows based on the specific screen's purpose.
|
|
74
|
-
|
|
75
|
-
Returns:
|
|
76
|
-
None
|
|
77
71
|
"""
|
|
78
72
|
raise NotImplementedError("Subclasses must implement build_table method.")
|
|
79
73
|
|
|
@@ -85,9 +79,6 @@ class TableScreen(ModalScreen):
|
|
|
85
79
|
|
|
86
80
|
Args:
|
|
87
81
|
event: The key event object.
|
|
88
|
-
|
|
89
|
-
Returns:
|
|
90
|
-
None
|
|
91
82
|
"""
|
|
92
83
|
if event.key in ("q", "escape"):
|
|
93
84
|
self.app.pop_screen()
|
|
@@ -111,7 +102,7 @@ class TableScreen(ModalScreen):
|
|
|
111
102
|
if cidx_name_value is None:
|
|
112
103
|
return
|
|
113
104
|
cidx, col_name, col_value = cidx_name_value
|
|
114
|
-
self.log(f"Filtering or viewing by {col_name} == {col_value}")
|
|
105
|
+
self.log(f"Filtering or viewing by `{col_name} == {col_value}`")
|
|
115
106
|
|
|
116
107
|
# Handle NULL values
|
|
117
108
|
if col_value == NULL:
|
|
@@ -123,11 +114,11 @@ class TableScreen(ModalScreen):
|
|
|
123
114
|
expr = pl.col(col_name) == col_value
|
|
124
115
|
value_display = f"[$success]{col_value}[/]"
|
|
125
116
|
|
|
126
|
-
df_filtered = self.dftable.df.
|
|
117
|
+
df_filtered = self.dftable.df.lazy().filter(expr).collect()
|
|
127
118
|
self.log(f"Filtered dataframe has {len(df_filtered)} rows")
|
|
128
119
|
|
|
129
|
-
|
|
130
|
-
if not
|
|
120
|
+
ok_rids = set(df_filtered[RID].to_list())
|
|
121
|
+
if not ok_rids:
|
|
131
122
|
self.notify(
|
|
132
123
|
f"No matches found for [$warning]{col_name}[/] == {value_display}",
|
|
133
124
|
title="No Matches",
|
|
@@ -135,18 +126,12 @@ class TableScreen(ModalScreen):
|
|
|
135
126
|
)
|
|
136
127
|
return
|
|
137
128
|
|
|
138
|
-
#
|
|
129
|
+
# Action filter
|
|
139
130
|
if action == "filter":
|
|
140
|
-
# Update selections
|
|
141
|
-
for i in range(len(self.dftable.selected_rows)):
|
|
142
|
-
self.dftable.selected_rows[i] = i in matched_indices
|
|
143
|
-
|
|
144
|
-
# Update main table display
|
|
145
131
|
self.dftable.do_filter_rows()
|
|
146
132
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
expr = [i in matched_indices for i in range(len(self.dftable.df))]
|
|
133
|
+
# Action view
|
|
134
|
+
else:
|
|
150
135
|
self.dftable.view_rows((expr, cidx, False, True))
|
|
151
136
|
|
|
152
137
|
# Dismiss the frequency screen
|
|
@@ -167,9 +152,6 @@ class RowDetailScreen(TableScreen):
|
|
|
167
152
|
|
|
168
153
|
Populates the table with column names and values from the selected row
|
|
169
154
|
of the main DataFrame. Sets the table cursor type to "row".
|
|
170
|
-
|
|
171
|
-
Returns:
|
|
172
|
-
None
|
|
173
155
|
"""
|
|
174
156
|
self.build_table()
|
|
175
157
|
|
|
@@ -181,6 +163,8 @@ class RowDetailScreen(TableScreen):
|
|
|
181
163
|
|
|
182
164
|
# Get all columns and values from the dataframe row
|
|
183
165
|
for col, val, dtype in zip(self.df.columns, self.df.row(self.ridx), self.df.dtypes):
|
|
166
|
+
if col == RID:
|
|
167
|
+
continue # Skip RID column
|
|
184
168
|
formatted_row = []
|
|
185
169
|
formatted_row.append(col)
|
|
186
170
|
|
|
@@ -208,20 +192,16 @@ class RowDetailScreen(TableScreen):
|
|
|
208
192
|
self.filter_or_view_selected_value(self.get_cidx_name_value(), action="filter")
|
|
209
193
|
event.stop()
|
|
210
194
|
elif event.key == "right_curly_bracket": # '}'
|
|
211
|
-
# Move to the next
|
|
195
|
+
# Move to the next row
|
|
212
196
|
ridx = self.ridx + 1
|
|
213
|
-
while ridx < len(self.df) and not self.dftable.visible_rows[ridx]:
|
|
214
|
-
ridx += 1
|
|
215
197
|
if ridx < len(self.df):
|
|
216
198
|
self.ridx = ridx
|
|
217
199
|
self.dftable.move_cursor_to(self.ridx)
|
|
218
200
|
self.build_table()
|
|
219
201
|
event.stop()
|
|
220
202
|
elif event.key == "left_curly_bracket": # '{'
|
|
221
|
-
# Move to the previous
|
|
203
|
+
# Move to the previous row
|
|
222
204
|
ridx = self.ridx - 1
|
|
223
|
-
while ridx >= 0 and not self.dftable.visible_rows[ridx]:
|
|
224
|
-
ridx -= 1
|
|
225
205
|
if ridx >= 0:
|
|
226
206
|
self.ridx = ridx
|
|
227
207
|
self.dftable.move_cursor_to(self.ridx)
|
|
@@ -270,12 +250,8 @@ class StatisticsScreen(TableScreen):
|
|
|
270
250
|
col_name = self.df.columns[self.col_idx]
|
|
271
251
|
lf = self.df.lazy()
|
|
272
252
|
|
|
273
|
-
# Apply only to visible rows
|
|
274
|
-
if False in self.dftable.visible_rows:
|
|
275
|
-
lf = lf.filter(self.dftable.visible_rows)
|
|
276
|
-
|
|
277
253
|
# Get column statistics
|
|
278
|
-
stats_df = lf.select(pl.col(col_name)).
|
|
254
|
+
stats_df = lf.select(pl.col(col_name)).describe()
|
|
279
255
|
if len(stats_df) == 0:
|
|
280
256
|
return
|
|
281
257
|
|
|
@@ -298,18 +274,14 @@ class StatisticsScreen(TableScreen):
|
|
|
298
274
|
|
|
299
275
|
def build_dataframe_stats(self) -> None:
|
|
300
276
|
"""Build statistics for the entire dataframe."""
|
|
301
|
-
lf = self.df.lazy()
|
|
302
|
-
|
|
303
|
-
# Apply only to visible rows
|
|
304
|
-
if False in self.dftable.visible_rows:
|
|
305
|
-
lf = lf.filter(self.dftable.visible_rows)
|
|
277
|
+
lf = self.df.lazy().select(pl.exclude(RID))
|
|
306
278
|
|
|
307
279
|
# Apply only to non-hidden columns
|
|
308
280
|
if self.dftable.hidden_columns:
|
|
309
281
|
lf = lf.select(pl.exclude(self.dftable.hidden_columns))
|
|
310
282
|
|
|
311
283
|
# Get dataframe statistics
|
|
312
|
-
stats_df = lf.
|
|
284
|
+
stats_df = lf.describe()
|
|
313
285
|
|
|
314
286
|
# Add columns for each dataframe column with appropriate styling
|
|
315
287
|
for idx, (col_name, col_dtype) in enumerate(zip(stats_df.columns, stats_df.dtypes), 0):
|
|
@@ -348,13 +320,11 @@ class FrequencyScreen(TableScreen):
|
|
|
348
320
|
def __init__(self, cidx: int, dftable: "DataFrameTable") -> None:
|
|
349
321
|
super().__init__(dftable)
|
|
350
322
|
self.cidx = cidx
|
|
351
|
-
self.sorted_columns = {
|
|
352
|
-
|
|
353
|
-
}
|
|
323
|
+
self.sorted_columns = {1: True} # Count sort by default
|
|
324
|
+
self.total_count = len(dftable.df)
|
|
354
325
|
|
|
355
|
-
|
|
356
|
-
self.
|
|
357
|
-
self.df: pl.DataFrame = df[df.columns[self.cidx]].value_counts(sort=True).sort("count", descending=True)
|
|
326
|
+
col = dftable.df.columns[self.cidx]
|
|
327
|
+
self.df: pl.DataFrame = dftable.df.lazy().select(pl.col(col).value_counts(sort=True)).unnest(col).collect()
|
|
358
328
|
|
|
359
329
|
def on_mount(self) -> None:
|
|
360
330
|
"""Create the frequency table."""
|
|
@@ -506,7 +476,8 @@ class MetaShape(TableScreen):
|
|
|
506
476
|
self.table.add_column(Text("Count", justify="right"))
|
|
507
477
|
|
|
508
478
|
# Get shape information
|
|
509
|
-
num_rows, num_cols = self.df.shape
|
|
479
|
+
num_rows, num_cols = self.df.shape if self.dftable.df_view is None else self.dftable.df_view.shape
|
|
480
|
+
num_cols -= 1 # Exclude RID column
|
|
510
481
|
dc_int = DtypeConfig(pl.Int64)
|
|
511
482
|
|
|
512
483
|
# Add rows to the table
|
|
@@ -543,11 +514,14 @@ class MetaColumnScreen(TableScreen):
|
|
|
543
514
|
|
|
544
515
|
# Add a row for each column
|
|
545
516
|
for idx, (col_name, col_type) in enumerate(schema.items(), 1):
|
|
517
|
+
if col_name == RID:
|
|
518
|
+
continue # Skip RID column
|
|
519
|
+
|
|
546
520
|
dc = DtypeConfig(col_type)
|
|
547
521
|
self.table.add_row(
|
|
548
522
|
dc_int.format(idx, thousand_separator=self.thousand_separator),
|
|
549
523
|
col_name,
|
|
550
|
-
dc_str.format(col_type, style=dc.style),
|
|
524
|
+
dc_str.format("Datetime" if str(col_type).startswith("Datetime") else col_type, style=dc.style),
|
|
551
525
|
)
|
|
552
526
|
|
|
553
527
|
self.table.cursor_type = "none"
|
|
@@ -119,9 +119,6 @@ class YesNoScreen(ModalScreen):
|
|
|
119
119
|
maybe: Optional Maybe button text/dict. Defaults to None.
|
|
120
120
|
no: Text or dict for the No button. If None, hides the No button. Defaults to "No".
|
|
121
121
|
on_yes_callback: Optional callable that takes no args and returns the value to dismiss with when Yes is pressed. Defaults to None.
|
|
122
|
-
|
|
123
|
-
Returns:
|
|
124
|
-
None
|
|
125
122
|
"""
|
|
126
123
|
super().__init__()
|
|
127
124
|
self.title = title
|
|
@@ -295,32 +292,26 @@ class SaveFileScreen(YesNoScreen):
|
|
|
295
292
|
|
|
296
293
|
CSS = YesNoScreen.DEFAULT_CSS.replace("YesNoScreen", "SaveFileScreen")
|
|
297
294
|
|
|
298
|
-
def __init__(
|
|
299
|
-
self
|
|
300
|
-
):
|
|
301
|
-
self.all_tabs = all_tabs or (all_tabs is None and multi_tab)
|
|
295
|
+
def __init__(self, filename: str, save_all: bool = False, tab_count: int = 1):
|
|
296
|
+
self.save_all = save_all
|
|
302
297
|
super().__init__(
|
|
303
|
-
title=
|
|
304
|
-
label="
|
|
298
|
+
title="Save to File",
|
|
299
|
+
label="Filename",
|
|
305
300
|
input=filename,
|
|
306
|
-
yes="Save",
|
|
307
|
-
maybe="Save All Tabs" if self.all_tabs else None,
|
|
301
|
+
yes=f"Save {tab_count} Tabs" if self.save_all else "Save Current Tab" if tab_count > 1 else "Save",
|
|
308
302
|
no="Cancel",
|
|
309
303
|
on_yes_callback=self.handle_save,
|
|
310
|
-
on_maybe_callback=self.handle_save,
|
|
311
304
|
)
|
|
312
305
|
|
|
313
306
|
def handle_save(self):
|
|
314
307
|
if self.input:
|
|
315
308
|
input_filename = self.input.value.strip()
|
|
316
309
|
if input_filename:
|
|
317
|
-
return input_filename, self.
|
|
310
|
+
return input_filename, self.save_all, True # Overwrite prompt
|
|
318
311
|
else:
|
|
319
312
|
self.notify("Filename cannot be empty", title="Save", severity="error")
|
|
320
313
|
return None
|
|
321
314
|
|
|
322
|
-
return None
|
|
323
|
-
|
|
324
315
|
|
|
325
316
|
class ConfirmScreen(YesNoScreen):
|
|
326
317
|
"""Modal screen to ask for confirmation."""
|
|
@@ -583,7 +574,7 @@ class EditColumnScreen(YesNoScreen):
|
|
|
583
574
|
self.df = df
|
|
584
575
|
super().__init__(
|
|
585
576
|
title="Edit Column",
|
|
586
|
-
label=f"
|
|
577
|
+
label=f"By value or Polars expression, e.g., abc, pl.lit(7), {NULL}, $_ * 2, $1 + $2, $_.str.to_uppercase(), pl.arange(0, pl.len())",
|
|
587
578
|
input="$_",
|
|
588
579
|
on_yes_callback=self._get_input,
|
|
589
580
|
)
|
|
@@ -607,8 +598,8 @@ class AddColumnScreen(YesNoScreen):
|
|
|
607
598
|
super().__init__(
|
|
608
599
|
title="Add Column",
|
|
609
600
|
label="Column name",
|
|
610
|
-
input="Link" if link else "
|
|
611
|
-
label2="Link template, e.g., https://example.com/$
|
|
601
|
+
input="Link" if link else "New column",
|
|
602
|
+
label2="Link template, e.g., https://example.com/$1/id/$_, PC/compound/$cid"
|
|
612
603
|
if link
|
|
613
604
|
else "Value or Polars expression, e.g., abc, pl.lit(123), NULL, $_ * 2, $1 + $total, $_ + '_suffix', $_.str.to_uppercase()",
|
|
614
605
|
input2="Link template" if link else "Value or expression",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dataframe-textual
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.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
|
|
@@ -325,7 +325,7 @@ zcat compressed_data.csv.gz | dv -f csv
|
|
|
325
325
|
|
|
326
326
|
| Key | Action |
|
|
327
327
|
|-----|--------|
|
|
328
|
-
| `\` | Select rows
|
|
328
|
+
| `\` | Select rows wth cell matches or those matching cursor value in current column |
|
|
329
329
|
| `\|` (pipe) | Select rows by expression |
|
|
330
330
|
| `{` | Go to previous selected row |
|
|
331
331
|
| `}` | Go to next selected row |
|
|
@@ -349,9 +349,9 @@ zcat compressed_data.csv.gz | dv -f csv
|
|
|
349
349
|
#### View & Filter
|
|
350
350
|
| Key | Action |
|
|
351
351
|
|-----|--------|
|
|
352
|
-
| `"` (quote) | Filter
|
|
353
|
-
| `v` | View rows (
|
|
354
|
-
| `V` | View
|
|
352
|
+
| `"` (quote) | Filter selected rows (others removed) |
|
|
353
|
+
| `v` | View selected rows (others hidden) |
|
|
354
|
+
| `V` | View selected by expression (others hidden) |
|
|
355
355
|
|
|
356
356
|
#### SQL Interface
|
|
357
357
|
|
|
@@ -411,8 +411,8 @@ Press `Enter` on any row to open a modal showing all column values for that row.
|
|
|
411
411
|
Useful for examining wide datasets where columns don't fit well on screen.
|
|
412
412
|
|
|
413
413
|
**In the Row Detail Modal**:
|
|
414
|
-
- Press `v` to **view** all rows containing the selected column value (
|
|
415
|
-
- Press `"` to **filter** all rows containing the selected column value (
|
|
414
|
+
- Press `v` to **view** all rows containing the selected column value (others hidden but preserved)
|
|
415
|
+
- Press `"` to **filter** all rows containing the selected column value (others removed)
|
|
416
416
|
- Press `{` to move to the **previous row** (respects hidden rows)
|
|
417
417
|
- Press `}` to move to the **next row** (respects hidden rows)
|
|
418
418
|
- Press `q` or `Escape` to close the modal
|
|
@@ -421,7 +421,7 @@ Useful for examining wide datasets where columns don't fit well on screen.
|
|
|
421
421
|
|
|
422
422
|
The application provides multiple modes for selecting rows (marks it for filtering or viewing):
|
|
423
423
|
|
|
424
|
-
- `\` - Select rows
|
|
424
|
+
- `\` - Select rows with cell matches or those matching cursor value in current column (respects data type)
|
|
425
425
|
- `|` - Opens dialog to select rows with custom expression
|
|
426
426
|
- `'` - Select/deselect current row
|
|
427
427
|
- `t` - Flip selections of all rows
|
|
@@ -591,8 +591,8 @@ Press `F` to see value distributions of the current column. The modal shows:
|
|
|
591
591
|
|
|
592
592
|
**In the Frequency Table**:
|
|
593
593
|
- Press `[` and `]` to sort by any column (value, count, or percentage)
|
|
594
|
-
- Press `v` to **
|
|
595
|
-
- Press `"` to **
|
|
594
|
+
- Press `v` to **view** all rows containing the selected value (others hidden but preserved)
|
|
595
|
+
- Press `"` to **filter** all rows containing the selected value (others removed)
|
|
596
596
|
- Press `q` or `Escape` to close the frequency table
|
|
597
597
|
|
|
598
598
|
This is useful for:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
dataframe_textual/__init__.py,sha256=E53fW1spQRA4jW9grxSqPEmoe9zofzr6twdveMbt_W8,1310
|
|
2
|
+
dataframe_textual/__main__.py,sha256=vgHjpSsHBF34UN46iMgu_EiebZUzxWwJZ_ngOU3nQvI,3412
|
|
3
|
+
dataframe_textual/common.py,sha256=gpNNY5ZePJkJPf-YoLSCHKaBpdXQ1yW2iSKYV6zZYUo,27908
|
|
4
|
+
dataframe_textual/data_frame_help_panel.py,sha256=UEtj64XsVRdtLzuwOaITfoEQUkAfwFuvpr5Npip5WHs,3381
|
|
5
|
+
dataframe_textual/data_frame_table.py,sha256=p7PXV-39IRimrzdbuDfiacK9yNQ7XXkWBFyZ4finEk8,147693
|
|
6
|
+
dataframe_textual/data_frame_viewer.py,sha256=fkiQ0OGi2rrE06VAVJuAM_9wwmqLY1AZouwEMNoDmy8,22367
|
|
7
|
+
dataframe_textual/sql_screen.py,sha256=P3j1Fv45NIKEYo9adb7NPod54FaU-djFIvCUMMHbvjY,7534
|
|
8
|
+
dataframe_textual/table_screen.py,sha256=XlVxU_haCxPoA41ZIDcwixOg341Wf35JrFwPoCTnMzE,19033
|
|
9
|
+
dataframe_textual/yes_no_screen.py,sha256=NI7Zt3rETDWYiT5CH_FDy7sIWkZ7d7LquaZZbX79b2g,26400
|
|
10
|
+
dataframe_textual-2.0.1.dist-info/METADATA,sha256=XUm9YBbqWaSjAGv8uOrAk8ss1blAjG30BLZwJn2IjwM,29306
|
|
11
|
+
dataframe_textual-2.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
12
|
+
dataframe_textual-2.0.1.dist-info/entry_points.txt,sha256=R_GoooOxcq6ab4RaHiVoZ4zrZJ-phMcGmlL2rwqncW8,107
|
|
13
|
+
dataframe_textual-2.0.1.dist-info/licenses/LICENSE,sha256=AVTg0gk1X-LHI-nnHlAMDQetrwuDZK4eypgSMDO46Yc,1069
|
|
14
|
+
dataframe_textual-2.0.1.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
dataframe_textual/__init__.py,sha256=IFPb8RMUgghw0eRomehkkC684Iny_gs1VkiZMQ5ZpFk,813
|
|
2
|
-
dataframe_textual/__main__.py,sha256=IcwIzLxAK26gMCUrwcrukaMzp_PRLzU7AwJ31sYW1Zo,3251
|
|
3
|
-
dataframe_textual/common.py,sha256=bV-8WdvAgctLlVWkFIhHLhZi6bIc0QcTo6odYgcB-JU,27735
|
|
4
|
-
dataframe_textual/data_frame_help_panel.py,sha256=iEKaur-aH1N_oqHu-vMwEEjfkjQiThK24UO5izsOiW0,3416
|
|
5
|
-
dataframe_textual/data_frame_table.py,sha256=NcKqhCYLtFbsly2mj_prqC31r5A4FYcfVHN2TVA5_XI,145800
|
|
6
|
-
dataframe_textual/data_frame_viewer.py,sha256=hqieMaogp0WmDvK4KqmvJHYAJXaFF6eATgn3msFkHug,22118
|
|
7
|
-
dataframe_textual/sql_screen.py,sha256=_1OZ552s2TV1R0XbsDsfIi1-C3TvggYASomLQoof-Ek,7401
|
|
8
|
-
dataframe_textual/table_screen.py,sha256=B0qrAu-rfZahjraMUJEc_kpDYJ0dGi9_xDwlIuTySlM,19742
|
|
9
|
-
dataframe_textual/yes_no_screen.py,sha256=HSWmP2rX4Y0hLNfrh3GXRAqsWhSif-jgoB9lo21jfNY,26559
|
|
10
|
-
dataframe_textual-1.16.2.dist-info/METADATA,sha256=bB4fNqszkMlyz8MURUgxN9wJ7F0JbhBDg00ojbeBmIQ,29331
|
|
11
|
-
dataframe_textual-1.16.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
12
|
-
dataframe_textual-1.16.2.dist-info/entry_points.txt,sha256=R_GoooOxcq6ab4RaHiVoZ4zrZJ-phMcGmlL2rwqncW8,107
|
|
13
|
-
dataframe_textual-1.16.2.dist-info/licenses/LICENSE,sha256=AVTg0gk1X-LHI-nnHlAMDQetrwuDZK4eypgSMDO46Yc,1069
|
|
14
|
-
dataframe_textual-1.16.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|