Skip to content

Instantly share code, notes, and snippets.

@horstjens
Last active December 20, 2020 07:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save horstjens/73d0d3e618830c8468fecb22b8a0e555 to your computer and use it in GitHub Desktop.
Save horstjens/73d0d3e618830c8468fecb22b8a0e555 to your computer and use it in GitHub Desktop.
haus design mit psimplegui Canvas für Lukas
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