HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Tkinter GUI for making very simple edits to pandas DataFrames

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
simplepandastkintereditsforverymakingguidataframes

Problem

(NOTE: Python2 only) It is part of a separate application that allows users to interact very loosely with different databases and check for possible errors and make corrections.

```
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
import tkFont

import pandas

class EditorApp:

def __init__(self, master, dataframe, edit_rows=[]):
""" master : tK parent widget
dataframe : pandas.DataFrame object"""
self.root = master
self.root.minsize(width=600, height=400)
self.root.title('database editor')

self.main = tk.Frame(self.root)
self.main.pack(fill=tk.BOTH, expand=True)

self.lab_opt = {'background': 'darkgreen', 'foreground': 'white'}

# the dataframe
self.df = dataframe
self.dat_cols = list(self.df)
if edit_rows:
self.dat_rows = edit_rows
else:
self.dat_rows = range(len(self.df))
self.rowmap = {i: row for i, row in enumerate(self.dat_rows)}

# subset the data and convert to giant list of strings (rows) for viewing
self.sub_data = self.df.ix[self.dat_rows, self.dat_cols]
self.sub_datstring = self.sub_data.to_string(
index=False, col_space=13).split('\n')
self.title_string = self.sub_datstring[0]

# save the format of the lines, so we can update them without re-running
# df.to_string()
self._get_line_format(self.title_string)

# fill in the main frame
self._fill()

# updater for tracking changes to the database
self.update_history = []

##################
# ADDING WIDGETS #
##################
def _fill(self):
self.canvas = tk.Canvas(self.main)
self.canvas.pack(fill=tk.BOTH, expand=tk.YES)

self._init_scroll()
self._init_lb()
self._pack_config_scroll()
self._pack_bind_lb()
self._fill_listbox()
self._make_editor_frame()
self._sel_mode()

##############
# SC

Solution

After starting the application for the first time it looks quite nice,
the code is readable even though it has some uncommon formatting.

For the UI, the first question that comes to my mind is: Why not use a
table widget? Intuitively that is a better fit for ... tabular data
than any other widget. That ties into the edit model: Selecting a row
and then having to manually choose the column from a drop down is
uncomfortable and takes too much time.

The undo button could do with a disabled state if there's no more undo
available.

The performance doesn't look completely bad, though it is very
noticeable with edit and undo operations. It depends on how much you
want to use this productively. Using a better widget or less wasteful
update operations come to mind.

Code

Formatting isn't quite PEP8
compatible, but it seems somewhat consistent. Just note that people
might object to it.

The names are quite short in many cases, making it harder to discern
what it relates to. E.g. lb and errmsg.

If possible you should also try to make the code compatible with
Python 3. In particular the print function should be used,
i.e. print("THIS ...").

The mode swapping operation and comparisons could more readibly done
with separate classes for the two modes, or at least with an enumeration
object
instead of comparing strings inline (which will be a problem once you
add a new value or decide to change the names).

The prev_vals member can be initialised inline with

self.prev_cals = {
    "col": self.col,
    "vals": {}
}


, which means less things to read. I'd recommend to follow the literal
style all the time unless there's a pressing need not to do it.

I have a whole number of other minor things as well, but I'd maybe start
with the bigger issues above before improving the small stuff.

Suggestions

If you're looking for more functional improvements, I'd recommend using
some other export functionality for the data frame than printing it,
e.g. CSV export, or something similar, possibly using a button on the UI
with file selection etc.

You could also package this so users of the library could edit a data
frame in their application with a single function invocation - a
functionality that seems useful in some scripts, or so.

Code Snippets

self.prev_cals = {
    "col": self.col,
    "vals": {}
}

Context

StackExchange Code Review Q#97332, answer score: 3

Revisions (0)

No revisions yet.