Last active
December 20, 2020 07:02
-
-
Save horstjens/73d0d3e618830c8468fecb22b8a0e555 to your computer and use it in GitHub Desktop.
haus design mit psimplegui Canvas für Lukas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import PySimpleGUI as sg | |
import numpy # for arange | |
import matplotlib.pyplot as plt | |
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg | |
import matplotlib | |
#sg.popup_get_text() | |
class Data: | |
corner = "NW" | |
land_x = 0 | |
land_y = 0 | |
land_area = 0 | |
house_bottomleft_x = 0 | |
house_bottomleft_y = 0 | |
house_x = 0 | |
house_y = 0 | |
bath_x = 0 | |
bath_y = 0 | |
house_area = 0 | |
bath_area = 0 | |
garden_area = 0 | |
#@classmethod | |
#def set(cls, key, value): | |
# """__set_attribute__ ony works for instances""" | |
# cls.key = value | |
@classmethod | |
def calculate(cls): | |
# ---- house --- | |
if cls.house_x != 0 and cls.house_y != 0 and cls.house_area != 0: | |
print("I can not (re)calculate house... set one value to zero and two values to non-zero") | |
elif cls.house_x != 0 and cls.house_y !=0: | |
cls.house_area = cls.house_x * cls.house_y | |
elif cls.house_x != 0 and cls.house_area != 0: | |
cls.house_y = cls.house_area / cls.house_x | |
elif cls.house_y != 0 and cls.house_area != 0: | |
cls.house_x = cls.house_area / cls.house_y | |
# ---- bath --- | |
if cls.bath_x != 0 and cls.bath_y != 0 and cls.bath_area != 0: | |
print("I can not (re)calculate bath.... set one value to zero and two values to non-zero") | |
elif cls.bath_x != 0 and cls.bath_y != 0: | |
cls.bath_area = cls.bath_x * cls.bath_y | |
elif cls.bath_x != 0 and cls.bath_area != 0: | |
cls.bath_y = cls.bath_area / cls.bath_x | |
elif cls.bath_y != 0 and cls.bath_area != 0: | |
cls.bath_x = cls.bath_area / cls.bath_y | |
# ---- land --- | |
if cls.land_x < cls.house_x + cls.house_bottomleft_x: | |
cls.land = cls.house_x + cls.house_bottomleft_x | |
if cls.land_y < cls.house_y + cls.house_bottomleft_y: | |
cls.land_y = cls.house_y + cls.house_bottomleft_y | |
if cls.land_x != 0 and cls.land_y != 0: | |
cls.land_area = cls.land_x * cls.land_y | |
elif cls.land_area != 0 and cls.land_x != 0: | |
cls.land_y = cls.land_area / cls.land_x | |
elif cls.land_area != 0 and cls.land_y != 0: | |
cls.land_x = cls.land_area / cls.land_y | |
# ---- garden ---- | |
cls.garden_area = cls.land_area - cls.house_area | |
# --- helper code to include matplotlib--- | |
def draw_figure(canvas, figure): | |
if canvas.children: # otherwise, the canvas grows bigger each time | |
for child in canvas.winfo_children(): | |
child.destroy() | |
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) | |
figure_canvas_agg.draw() | |
figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1) | |
return figure_canvas_agg | |
def line_plot(dataA, dataB, titlestring, xinch=5, yinch=5, res=100,): | |
"""create a line plot diagram""" | |
fi, ax = plt.subplots(figsize=(xinch, yinch), dpi=res) # inch x inch y, dpi | |
if len(dataA) != len(dataB): | |
raise ValueError("data A must have same length as data B") | |
t = range(len(dataA)) | |
ax.plot(t, dataA, label="a-werte") | |
ax.plot(t, dataB, label="b-werte") | |
ax.legend() | |
ax.grid() | |
ax.set(title = titlestring, xlabel = "a", ylabel="b") | |
ax.axhline(y=0, color='r', linestyle='dashed', linewidth=2) | |
#rot = 0 if (len(dataA) < 20) else 90 # rotation of font in x-axis | |
#plt.xticks(range(len(dataA) + 1, 1), rotation=rot) | |
fig = plt.gcf() | |
return fig | |
### | |
# fig3 = line_plot(dataA, dataB, "hp over time", 12.1, 3, 100) | |
# fig_canvas_agg = draw_figure(window['CANVAS3'].TKCanvas, fig3) | |
#sg.Output() | |
def form_to_data(): | |
"""copy data from the form into the Data class""" | |
#for v in ["house_x", "house_y", "house_area", "bath_x","bath_y", "bath_area"]: | |
for v in [k for k in Data.__dict__.keys() if "__" not in k]: | |
print("processing v:",v) | |
if v not in values: | |
continue | |
if values[v] is None or values[v] == "": | |
setattr(Data, v, 0) | |
else: | |
# corner is the only string inside Data. everything else is a float | |
if v == "corner": | |
setattr(Data, v, values[v]) | |
else: | |
setattr(Data, v, float(values[v])) | |
#Data.house_x = float(values["house_x"]) | |
#Data.house_y = float(values["house_y"]) | |
#Data.house_ara = float(values["house_area"]) | |
#Data.bath_x = float(values["bath_x"]) | |
#Data.bath_y = float(values["bath_y"]) | |
#Data.bath_area = float(values["bath_area"]) | |
#Data.my_corner = mycorner # because mycorner is not a number AND is not bound to a single widget | |
def data_to_form(): | |
"""copy data from Data class into form""" | |
# handle corner first because both radio and combo field depend on it | |
window["corner"].update(Data.corner) | |
# set all radio buttons to false | |
window["radio_NW"].update(False) | |
window["radio_NE"].update(False) | |
window["radio_SW"].update(False) | |
window["radio_SE"].update(False) | |
# set the correct radio button to True | |
window["radio_" + Data.corner].update(True) | |
# ---- copy Data dict into form --- | |
for v in [k for k in Data.__dict__.keys() if "__" not in k]: | |
print("writing back:",v) | |
if v not in values: | |
continue | |
if v != "corner": | |
window[v].update(getattr(Data, v)) | |
#window["house_x"].update(Data.house_x) | |
#window["house_y"].update(Data.house_y) | |
#window["house_area"].update(Data.house_area) | |
#window["bath_x"].update(Data.bath_x) | |
#window["bath_y"].update(Data.bath_y) | |
#window["bath_area"].update(Data.bath_area) | |
# --- result --- | |
window["result_house1"].update("{:>10.2f} [m] x {:>10.2f} [m] = ".format(Data.house_x, Data.house_y, )) | |
window["result_bath1"].update( "{:>10.2f} [m] x {:>10.2f} [m] = ".format(Data.bath_x, Data.bath_y, )) | |
window["result_house"].update("{:>6.2f} [m²]".format(Data.house_area)) | |
window["result_bath"].update("{:>6.2f} [m²]".format(Data.bath_area)) | |
window["result_garden"].update("{:>6.2f} [m²]".format(Data.garden_area)) | |
#window["result_house"].update("Result house {}x{}={}m²".format(Data.house_x, Data.house_y, Data.house_area)) | |
#window["result_bath"].update("Result bath {}x{}={}m²".format(Data.bath_x, Data.bath_y, Data.bath_area)) | |
#window["result_garden"].update("Result garden {}m²".format(Data.garden_area)) | |
def draw_stuff(): | |
window["plot"].erase() # erase everything on Graph | |
#window["plot"].delete_figure(old_garden) | |
#window["plot"].delete_figure(old_house) | |
#window["plot"].delete_figure(old_bath) | |
#sg.Graph.delete_figure() | |
# testing if drawing is possible.. | |
print("drawing land and garden") | |
#window["plot"].draw_rectangle() | |
# canvas is 200x200, always center. | |
start_x = values["xslider"]//2 - Data.land_x // 2 | |
start_y = values["yslider"]//2 - Data.land_y // 2 | |
garden = window["plot"].draw_rectangle( | |
top_left=(start_x, start_y + Data.land_y ), | |
bottom_right=(start_x + Data.land_x, start_y), | |
fill_color="green") | |
print("drawing house") | |
house = window["plot"].draw_rectangle( | |
top_left=(start_x + Data.house_bottomleft_x, start_y + Data.house_bottomleft_y + Data.house_y), | |
bottom_right=(start_x + Data.house_bottomleft_x + Data.house_x, start_y + Data.house_bottomleft_y), | |
fill_color="brown") | |
print("drawing bath") | |
if Data.corner == "SW": | |
start_bath_x = 0 | |
start_bath_y = 0 | |
elif Data.corner == "SE": | |
start_bath_x = Data.house_x - Data.bath_x | |
start_bath_y = 0 | |
elif Data.corner == "NE": | |
start_bath_x = Data.house_x - Data.bath_x | |
start_bath_y = Data.house_y - Data.bath_y | |
elif Data.corner == "NW": | |
start_bath_x = 0 | |
start_bath_y = Data.house_y - Data.bath_y | |
else: | |
raise ValueError("no good Data.corner:", Data.corner) | |
bath = window["plot"].draw_rectangle( | |
top_left=(start_x + Data.house_bottomleft_x + start_bath_x, | |
start_y + Data.house_bottomleft_y + start_bath_y+ Data.bath_y), | |
bottom_right=(start_x + Data.house_bottomleft_x + start_bath_x + Data.bath_x, | |
start_y + Data.house_bottomleft_y + start_bath_y), | |
fill_color="blue") | |
# --- draw grid --- | |
if values["grid"]: | |
for x in numpy.arange(start_x, values["xslider"], values["gridsize"]): | |
window["plot"].draw_line(point_from=(x,0), point_to=(x, values["yslider"]), color="white") | |
for y in numpy.arange(start_y, values["yslider"], values["gridsize"]): | |
window["plot"].draw_line(point_from=(0, y), point_to=(values["xslider"],y), color="white") | |
return garden, house, bath # references to the figures | |
def recalc(): | |
# --- make this always ---- | |
#print("my corner:", my_corner) | |
#print("form values:",values) | |
form_to_data() | |
#print("data class:", Data.__dict__) | |
# calculate house | |
print("calculating...") | |
Data.calculate() | |
#print("data class:", Data.__dict__) | |
data_to_form() | |
#print("drawing...") | |
# test if drawing is possible | |
# .. TODO | |
#draw_stuff() | |
col_left=sg.Column([ | |
[sg.Text("land_x [m]")], | |
[sg.Text("land_y [m]")], | |
[sg.Text("land_area [m²]")], | |
[sg.HorizontalSeparator()], | |
[sg.Text("house_x [m]")], | |
[sg.Text("house_y [m]")], | |
[sg.Text("house_area [m²]")], | |
[sg.HorizontalSeparator()], | |
[sg.Text("bath_x [m]")], | |
[sg.Text("bath_y [m]")], | |
[sg.Text("bath_area [m²]")], | |
[sg.HorizontalSeparator()], | |
[sg.Text("corner of bath")], | |
[sg.Text(" ")], | |
[sg.HorizontalSeparator()], | |
[sg.Text("house_bottomleft_x [m]")], | |
[sg.Text("house_bottomleft_y [m]")], | |
[sg.HorizontalSeparator()], | |
]) | |
col_right = sg.Column([ | |
[sg.InputText("25", key="land_x", size=(35, 0), enable_events=False)], | |
[sg.InputText("25", key="land_y", size=(35, 0), enable_events=False)], | |
[sg.InputText("0", key="land_area", size=(35, 0), enable_events=False)], | |
[sg.HorizontalSeparator()], | |
[sg.InputText("15", key="house_x", size=(35,0), enable_events=False)], | |
[sg.InputText("12", key="house_y", size=(35,0), enable_events=False)], | |
[sg.InputText("0", key="house_area", size=(35,0), enable_events=False)], | |
[sg.HorizontalSeparator()], | |
[sg.InputText("2.5", key="bath_x", size=(35,0), enable_events=False)], | |
[sg.InputText("1.5", key="bath_y", size=(35,0), enable_events=False)], | |
[sg.InputText("0", key="bath_area", size=(35,0), enable_events=False)], | |
[sg.HorizontalSeparator()], | |
[sg.Radio("NW", key="radio_NW", group_id="cornergroup", enable_events=True), | |
sg.Radio("NE", key="radio_NE", group_id="cornergroup", enable_events=True), | |
sg.Radio("SW", key="radio_SW", group_id="cornergroup", enable_events=True), | |
sg.Radio("SE", key="radio_SE", group_id="cornergroup", enable_events=True), | |
], | |
[sg.Combo(["NW","NE","SW","SE"], default_value="NW", key="corner", size=(4,0), enable_events=True)], | |
[sg.HorizontalSeparator()], | |
[sg.InputText("0", key="house_bottomleft_x", size=(35, 0), enable_events=False)], | |
[sg.InputText("0", key="house_bottomleft_y", size=(35, 0), enable_events=False)], | |
[sg.HorizontalSeparator()], | |
]) | |
col_plot = sg.Column([ | |
[sg.Text("^ y-axis"), sg.Checkbox("grid", False, enable_events=True,key="grid"), | |
sg.Text("every"), sg.Slider(range=[0.5, 10.0 ], default_value=5, resolution=0.5, orientation="horizontal", size=(17,5), key="gridsize", enable_events=True), sg.Text("meters")], | |
[sg.Slider((10,200),30, 5, 20, "vertical",enable_events=True,size=(15,4), key="yslider",), | |
sg.Column([ | |
[sg.Slider((10,200),30, 5, 20, "horizontal",enable_events=True,size=(30,4), key="xslider",), | |
sg.Text("--> x Axis")], | |
[sg.Graph(canvas_size=(400,300), | |
graph_bottom_left=(0,0), | |
graph_top_right=(30,30), | |
background_color="black", | |
key="plot")], | |
]), | |
], | |
]) | |
layout = [ | |
[sg.Text("Welcome. Click [recalculate] to redraw. Always fill out 2 of 3 from (x,y,area) to calculate the missing value")], | |
[col_left,col_right, col_plot], | |
[sg.Column([ | |
[sg.Text("Reslt house", justification="left", text_color="yellow")], | |
[sg.Text("Reslt bath", justification="left", text_color="yellow")], | |
[sg.Text("Reslt garden", justification="left", text_color="yellow")], | |
]), | |
sg.Column([ | |
[sg.Text("{:>10.2f} [m] x {:>10.2f} [m] = ".format(Data.house_x, Data.house_y,), key="result_house1", size=(30,0), justification="right")], | |
[sg.Text("{:>10.2f} [m] x {:>10.2f} [m] = ".format(Data.bath_x, Data.bath_y,), key="result_bath1", size=(30,0), justification="right")], | |
[sg.Text("= ", size=(30,0), justification="right")], | |
]), | |
sg.Column([ | |
[sg.Text("{:>6.2f} [m²]".format(Data.house_area), key="result_house", size=(10,0), justification="right", text_color="yellow")], | |
[sg.Text("{:>6.2f} [m²]".format(Data.bath_area), key="result_bath",size=(10,0), justification="right", text_color="yellow" )], | |
[sg.Text("{:>6.2f} [m²]".format(Data.garden_area), key="result_garden", size=(10,0), justification="right", text_color="yellow")], | |
]) | |
], | |
[sg.Button("recalculate", bind_return_key=True), sg.Button("Cancel"), sg.Button("matplot"),], | |
[sg.Canvas(key="CANVAS4")], | |
] | |
window = sg.Window("Architect", layout=layout, font=("Helvetica", 12)) | |
window.Finalize() | |
garden,house,bath = None,None,None | |
my_corner = "NW" | |
while True: | |
event, values = window.read() | |
if event == sg.WIN_CLOSED or event == "Cancel": | |
break | |
if event == "recalculate": | |
print("recalculating...") | |
recalc() | |
draw_stuff() | |
if "radio" in event: | |
my_corner = event[-2:] | |
print("corner is:", my_corner) | |
print("radio is set to:", my_corner) | |
window["corner"].update(my_corner) | |
#event, values = window.read() | |
#print(values) | |
if "slider" in event: | |
window["plot"].change_coordinates(graph_bottom_left=(0,0), graph_top_right=(values["xslider"], values["yslider"])) | |
draw_stuff() | |
if "grid" in event: | |
draw_stuff() | |
if event == "corner": | |
my_corner = values["corner"] | |
print("combo is set to", my_corner) | |
window["radio_NW"].update(False) | |
window["radio_NE"].update(False) | |
window["radio_SW"].update(False) | |
window["radio_SE"].update(False) | |
window["radio_"+my_corner].update(True) | |
#event, values = window.read() | |
if event == "matplot": | |
# calculate and update a matplotlib canvas | |
data_a = [1,2,3 ,4, 5,6,7, 8,9,10,15] | |
data_b = [0,5,-2,4,23,0,9,-1,3,2, 4] | |
fig3 = line_plot(data_a, data_b, "zufallswerte", 12.1, 3, 100) | |
fig_canvas_agg = draw_figure(window['CANVAS4'].TKCanvas, fig3) | |
#print("house: x: {house_x} y: {house_y} ) | |
window.close() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment