Handy graphical user interface library for daily use
Project description
Pancake Kit
Pancake Kit aims to provide a handy user interface to your Python codes. It provides GUI as a lightweight web app powered by Flask.
Installation
pip3 install pancakekit
Quick Tasting
Assume that there is a function that calculates the nth Fibonacci number. In three steps, you can prepare a GUI that wraps this function.
from pancakekit import Pancake
def fibonacci(n=10):
return (fibonacci(n-1) + fibonacci(n-2)) if n >= 2 else n
cake = Pancake() # Step 1: Make a Pancake instance.
cake.add(fibonacci) # Step 2: Add your function to the pancake.
cake.serve() # Step 3: Serve the cake.
When you open http://127.0.0.1:8000/
in a web browser, you will find an input box for entering n
and a button that invokes fibonacci()
.
Adding toppings
In Pancake Kit, a Pancake instance corresponds to a single web page. Each UI component is added to the pancake as a Topping instance.
Value
cake.add({"a": 0, "b": 1}) # Dictionary -> Multiple inputs
cake.add("a:") # String ends with ":" -> Value input with the string as a label
cake.add("abc") # String/Number -> Non-editable text
Value with @decorator
cake.add("abc@slider(0, 1, 0.1):0.5") # @slider(range_min, range_max, [step])[:value] -> Slider
Special object
cake.add(image) # PIL.Image/Path string -> Image view
cake.add(df) # pandas.DataFrame -> Table
Function
def f(a, b, c):
return a * b + c
cake.add(f) # Function -> Multiple inputs & execution button
Equivalently, you can decorate the function with a decorator @cake.topping
:
@cake.topping
def f(a, b, c):
return a * b + c
Use Pancake Kit in the interactive mode
In the interactive mode, you can perform on-site decoration on your pancake.
# On the Terminal or Command Prompt
from pancakekit import *
cake = Pancake()
cake.serve()
# -> You will find a blank page on http://127.0.0.1:8000/.
d = cake.add({"a": 1, "b":2, "c":3})
# -> A dictionary input appears on the page immediately.
d.value_changed = cake.show_message
# -> As you change the values of the input, you will see a pop-up message.
As a shortcut to the instantiation & cake.serve(), you can use MagicPancake. The additional feature of the MagicPancake is that you can access the value of a topping by its name.
from pancakekit import *
cake = MagicPancake()
cake.add("myinput", name="a")
cake.a = 10
cake["a"].value_changed = lambda: cake.show_message(cake.a)
More conveniently, execute
python3 -m pancakekit
where the cake
object and all the toppings in pancakekit
have already been loaded as local variables.
How to
Adding a PancakeKit topping
You can add your favorite toppings to your pancake, as in the following example:
from pancakekit import Pancake, Button, Label
cake = Pancake()
button = cake.add(Button(0))
label = cake.add(Label(1))
def button_click(x):
button.value = label.value
label.value += x
button.clicked = button_click
cake.serve()
Here, when a clicked
event is sent to button_click
, the value of the button is passed as an argument. The value of the topping can be changed by assigning a value to the value
property.
Responding to user actions
When a user changes the value of the toppings from the browser, the callback function specified by topping.value_changed
is invoked.
from pancakekit import *
cake = Pancake()
dict_input = cake.add({"a": 1, "b": 2, "c": 3})
dict_input.value_changed = lambda: cake.show_message(dict_input.value)
cake.serve()
Note that cake.show_message()
will pop up a message in the browser.
Accessing a topping by its name
You can access the toppings in the cake by their names.
from pancakekit import *
cake = Pancake()
cake.add(Slider("a", range_min=0, range_max=20), name="slider0")
cake.add(Slider("b", range_min=0, range_max=20), name="slider1")
cake["slider0"].value_changed = lambda x: setattr(cake["slider1"], "value", x+5)
cake["slider1"].value_changed = lambda x: setattr(cake["slider0"], "value", x*2)
cake.serve()
MagicCard
By holding down the shift key and pressing the return key, MagicCard appears with a text box. You can execute the code in the textbox by the command/control key + return. The pancake can be referred to as cake
. Try the following to see if it actually works.
cake.add(Button("Hi"))
cake(cake.toppings) # In the magic card, the direct call of cake() pops up a message.
Toppings
Toppings for user interaction
Button(title: str)
btn = cake.add(Button("Button"))
btn.clicked = lambda x: print(x)
btn.value = "My button"
Input(label: str, default=None, placeholder=None)
myinput = cake.add(Input("input", default=1))
myinput.value_changed = lambda x: print(x)
myinput.value += 1
DictInput(input_dict: dict)
dict_input = cake.add(DictInput({"a": 0, "b": 2}))
print(dict_input.value) # -> {"a": 0, "b": 2}
dict_input["a"] = 1
print(dict_input["a"]) # -> 1
dict_input.value_changed = cake.show_message
Slider(key: str, range_min: float, range_max: float, value: float=None)
slider = cake.add(Slider("myslider", range_min=0, range_max=10, value=5))
slider.value_changed = cake.show_message
Toppings for display
Label(text: str)
Text(text: str)
Paragraph(text: str)
ImageView(image: PIL.Image|str)
- image argument should be PIL.Image or a path to a image file.
ImageCard(image: PIL.Image|str)
Table(df: pandas.DataFrame)
Toppings for arrangement
Row()
cake = Pancake()
row = cake.add(Row())
my_input = row.add(Input("Input"))
button = row.add(Button("Go!"))
button.clicked = lambda: cake.show_message(my_input.value)
Column()
cake = Pancake()
column = cake.add(Column())
my_input = column.add(Input("Input"))
button = column.add(Button("Go!"))
button.clicked = lambda: cake.show_message(my_input.value)
Card()
Make its content draggable such as ImageCard.
cake = Pancake()
card = cake.add(Card())
row = card.add(Row())
for key in ["a", "b", "c"]:
row.add(Slider(key, 0, 10))
FloatingCard()
A Card topping floating above other toppings with a classic-style draggable handle.
Automated toppings
FromFunction(function)
Serving multiple pancakes
As you know, a pacanke should be served on a plate. That is,
from pancakekit import *
plate = Plate()
class Crape(Pancake):
def decorate(self):
b = self.add(Button("I want to have a waffle!"))
b.clicked = lambda: plate.go_to("Waffle")
def show_up(self):
plate.cake["greediness"].value += 1
class Waffle(Pancake):
def decorate(self):
b = self.add(Button("I want to have a taiyaki!"))
b.clicked = lambda: plate.go_to("Taiyaki")
def show_up(self):
plate.cake["greediness"].value += 2
class Taiyaki(Pancake):
def decorate(self):
b = self.add(Button("I want to have a crape!"))
b.clicked = lambda: plate.go_to("Crape")
def show_up(self):
plate.cake["greediness"].value += 3
Crape(plate)
Waffle(plate)
Taiyaki(plate)
plate.cake.add(Label("Greediness:"))
plate.cake.add(0, name="greediness")
plate.serve()
When subclassing Pancake, describe the procedure to be performed once when instantiating in the decorate()
and the procedure to be performed each time the page is displayed in show_up()
.
Making a custom topping
One of the simplest custom topping is as follows:
class MyLabel(Topping):
def prepare(self, text):
self.value = text
style = {"text-shadow": f"1px 1px 1px #bbb"}
self.label = Tag("label", style = style, value_ref=self)
def html(self):
return self.label.render()
prepare(self, *args, **kwargs)
is called once when the topping is added to a pancake. html(self)
returns a HTML string to be rendered.
Other than prepare
and html
, you can override the following methods:
-
value_getter(self) -> Any
This method returns a value of the topping. The default behavior is to return
self._value
. -
value_preprocessor(self, value: Any) ->Any
This method processes
value
and returns a value to be stored inself._value
. The default behavior is to returnvalue
. -
web_value_preprocessor(self, tag: Tag, value: Any) ->Any
This method processes
value
from the browser input and returns a value to be stored inself._value
. The default behavior is to returnvalue
. -
event_preprocessor(self, event: Event)->Any
This value processes event and returns a value to be passed to an user-defined function. The default behavior is to return
event.value
.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.