use math.floor instead of int when converting for Graph Element
This commit is contained in:
parent
4f7a53bbf8
commit
24d7e6bab2
|
@ -1,6 +1,6 @@
|
|||
#!/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'
|
||||
|
||||
|
@ -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 random import randint
|
||||
import warnings
|
||||
from math import floor
|
||||
|
||||
warnings.simplefilter('always', UserWarning)
|
||||
|
||||
|
@ -3039,7 +3040,7 @@ class Graph(Element):
|
|||
if self.FloatValues:
|
||||
return new_x, new_y
|
||||
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):
|
||||
"""
|
||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue