use math.floor instead of int when converting for Graph Element

This commit is contained in:
PySimpleGUI 2019-12-17 17:51:48 -05:00
parent 4f7a53bbf8
commit 24d7e6bab2
2 changed files with 253 additions and 2 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3 #!/usr/bin/python3
version = __version__ = "4.12.0.2 Unreleased - Element.expand added expand_row parm, spin - defaults to first entry if none specified" version = __version__ = "4.12.0.3 Unreleased - Element.expand added expand_row parm, spin - defaults to first entry if none specified, use math.floor to convert in Graph element"
port = 'PySimpleGUI' port = 'PySimpleGUI'
@ -123,6 +123,7 @@ import inspect
# from typing import List, Any, Union, Tuple, Dict # because this code has to run on 2.7 can't use real type hints. Must do typing only in comments # from typing import List, Any, Union, Tuple, Dict # because this code has to run on 2.7 can't use real type hints. Must do typing only in comments
from random import randint from random import randint
import warnings import warnings
from math import floor
warnings.simplefilter('always', UserWarning) warnings.simplefilter('always', UserWarning)
@ -3039,7 +3040,7 @@ class Graph(Element):
if self.FloatValues: if self.FloatValues:
return new_x, new_y return new_x, new_y
else: else:
return int(new_x), int(new_y) return floor(new_x), floor(new_y)
def DrawLine(self, point_from, point_to, color='black', width=1): def DrawLine(self, point_from, point_to, color='black', width=1):
""" """

View File

@ -0,0 +1,250 @@
"""
Code Counter
A program that counts the lines of code and code characters in a code-base
Author : Israel Dryer
Modified : 2019-11-01
You can find the original repository with the latest updates here:
https://github.com/israel-dryer/Code-Counter
"""
import PySimpleGUI as sg
import statistics as stats
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
WINDOW_SIZE = (1280, 720)
def clean_data(window):
""" clean and parse the raw data """
raw = window.AllKeysDict['INPUT'].DefaultText.split('\n')
# remove whitespace
data = [row.strip() for row in raw if row.strip()]
# remove hash comments
stage1 = []
for row in data:
if row.find('#') != -1:
stage1.append(row[:row.find('#')])
else:
stage1.append(row)
# remove " multiline comments
stage2 = []
ml_flag = False # multiline comment flag
for row in stage1:
if row.count(r'"""') == 0 and not ml_flag: # not a comment line
stage2.append(row)
elif row.count(r'"""') == 1 and not ml_flag: # starting comment line
ml_flag = True
stage2.append(row[:row.find('"""')])
elif row.count(r'"""') == 1 and ml_flag: # ending comment line
ml_flag = False
stage2.append(row[row.find('"""') + 1:])
else:
continue
# remove ' multiline comments
stage3 = []
ml_flag = False # multiline comment flag
for row in stage2:
if row.count(r"'''") == 0 and not ml_flag: # not a comment line
stage3.append(row)
elif row.count(r"'''") == 1 and not ml_flag: # starting comment line
ml_flag = True
stage3.append(row[:row.find("'''")])
elif row.count(r"'''") == 1 and ml_flag: # ending comment line
ml_flag = False
stage3.append(row[row.find("'''") + 1:])
else:
continue
clean_code = [row for row in stage3 if row not in ('', "''", '""')]
# row and character rounds / for calc stats, histogram, charts
char_cnt = [len(row) for row in clean_code]
# statistics
if len(clean_code) == 0:
char_per_line = 1
else:
char_per_line = sum(char_cnt) // len(clean_code)
code_stats = {
'lines': len(clean_code), 'char_per_line': char_per_line,
'count': sum(char_cnt), 'mean': stats.mean(char_cnt), 'median': stats.median(char_cnt),
'pstdev': stats.pstdev(char_cnt), 'min': min(char_cnt), 'max': max(char_cnt)}
return clean_code, char_cnt, code_stats
def process_data(window):
""" clean and save data ... previous executed manually with submit button """
# try:
clean_code, char_cnt, code_stats = clean_data(window)
save_data(clean_code, code_stats, window)
display_charts(char_cnt, window)
display_stats(code_stats, window)
window['T2'].select()
def save_data(clean_code, code_stats, window):
window['OUTPUT'].update('\n'.join([row for row in clean_code]))
return
""" save clean code and stats to file """
with open('output.txt', 'w') as f:
for row in clean_code:
f.write(row + '\n')
# update display
with open('output.txt', 'r') as f:
window['OUTPUT'].update(f.read())
def display_charts(char_cnt, window):
""" create charts to display in window """
def draw_figure(canvas, figure, loc=(0, 0)):
""" matplotlib helper function """
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
figure_canvas_agg.draw()
figure_canvas_agg.get_tk_widget().pack()
return figure_canvas_agg
figure = plt.figure(num=1, figsize=(4, 5))
# histogram
plt.subplot(211)
plt.hist(char_cnt)
plt.title('character count per line')
plt.ylabel('frequency')
plt.tight_layout()
# line plot
plt.subplot(212)
x = range(0, len(char_cnt))
y = char_cnt
plt.plot(y)
plt.fill_between(x, y)
plt.title('compressed code line counts')
plt.xlabel('code line number')
plt.ylabel('number of characters')
plt.tight_layout()
draw_figure(window['IMG'].TKCanvas, figure)
def display_stats(code_stats, window):
""" display code stats in the window """
window['LINES'].update('{:,d}'.format(code_stats['lines']))
window['CHARS'].update('{:,d}'.format(code_stats['count']))
window['CPL'].update('{:,d}'.format(code_stats['char_per_line']))
window['MEAN'].update('{:,.0f}'.format(code_stats['mean']))
window['MEDIAN'].update('{:,.0f}'.format(code_stats['median']))
window['PSTDEV'].update('{:,.0f}'.format(code_stats['pstdev']))
window['MAX'].update('{:,d}'.format(code_stats['max']))
window['MIN'].update('{:,d}'.format(code_stats['min']))
def click_file(window):
""" file button click event; open file and load to screen """
filename = sg.popup_get_file('Select a file containing Python code:', title='Code Counter')
if filename is None:
return
with open(filename) as f:
raw = f.read()
window['INPUT'].update(raw)
def click_clipboard(window):
""" get data from clipboard and paste to input """
try:
clip = window['INPUT'].Widget.clipboard_get()
window['INPUT'].update(clip)
except:
sg.popup_error('Clipboard is empty', no_titlebar=True)
def click_reset(window):
""" reset the windows and data fields """
window['INPUT'].update('')
window['OUTPUT'].update('')
reset_stats(window)
window['T1'].select()
def reset_stats(window):
""" clear the stats fields """
window['LINES'].update('{:,d}'.format(0))
window['CHARS'].update('{:,d}'.format(0))
window['CPL'].update('{:,d}'.format(0))
window['MEAN'].update('{:,.0f}'.format(0))
window['MEDIAN'].update('{:,.0f}'.format(0))
window['PSTDEV'].update('{:,.0f}'.format(0))
window['MAX'].update('{:,d}'.format(0))
window['MIN'].update('{:,d}'.format(0))
def btn(name, **kwargs):
""" create button with default settings """
return sg.Button(name, size=(16, 1), font=(sg.DEFAULT_FONT, 12), **kwargs)
def stat(text, width=10, relief=None, justification='left', key=None):
elem = sg.Text(text, size=(width, 1), relief=relief, justification=justification, key=key)
return elem
def main():
""" main program and GUI loop """
sg.ChangeLookAndFeel('BrownBlue')
tab1 = sg.Tab('Raw Code',
[[sg.Multiline(key='INPUT', pad=(0, 0), font=(sg.DEFAULT_FONT, 12))]],
background_color='gray', key='T1')
tab2 = sg.Tab('Clean Code',
[[sg.Multiline(key='OUTPUT', pad=(0, 0), font=(sg.DEFAULT_FONT, 12))]],
background_color='gray25', key='T2')
stat_col = sg.Column([
[stat('Lines of code'), stat(0, 8, 'sunken', 'right', 'LINES'),
stat('Total chars'), stat(0, 8, 'sunken', 'right', 'CHARS')],
[stat('Chars per line'), stat(0, 8, 'sunken', 'right', 'CPL'),
stat('Mean'), stat(0, 8, 'sunken', 'right', 'MEAN')],
[stat('Median'), stat(0, 8, 'sunken', 'right', 'MEDIAN'),
stat('PStDev'), stat(0, 8, 'sunken', 'right', 'PSTDEV')],
[stat('Max'), stat(0, 8, 'sunken', 'right', 'MAX'),
stat('Min'), stat(0, 8, 'sunken', 'right', 'MIN')]], pad=(5, 10), key='STATS')
lf_col = [
[btn('Load FILE'), btn('Clipboard'), btn('RESET')],
[sg.TabGroup([[tab1, tab2]], title_color='black', key='TABGROUP')]]
rt_col = [
[sg.Text('LOAD a file or PASTE code from Clipboard', pad=(5, 15))],
[sg.Text('Statistics', size=(20, 1), pad=((5, 5), (15, 5)),
font=(sg.DEFAULT_FONT, 14, 'bold'), justification='center')],
[stat_col],
[sg.Text('Visualization', size=(20, 1),
font=(sg.DEFAULT_FONT, 14, 'bold'), justification='center')],
[sg.Canvas(key='IMG')]]
layout = [[sg.Column(lf_col, element_justification='left', pad=(0, 10), key='LCOL'),
sg.Column(rt_col, element_justification='center', key='RCOL')]]
window = sg.Window('Code Counter', layout, resizable=True, size=WINDOW_SIZE, finalize=True)
for elem in ['INPUT', 'OUTPUT', 'LCOL', 'TABGROUP']:
window[elem].expand(expand_x=True, expand_y=True)
# main event loop
while True:
event, values = window.read()
if event is None:
break
if event == 'Load FILE':
click_file(window)
process_data(window)
if event == 'Clipboard':
click_clipboard(window)
process_data(window)
if event == 'RESET':
click_reset(window)
if __name__ == '__main__':
main()