|
""" |
|
Streamlit application |
|
""" |
|
from loguru import logger |
|
import mpld3 |
|
import streamlit as st |
|
import streamlit.components.v1 as components |
|
from streamlit.errors import StreamlitAPIException |
|
import yaml |
|
import lsystc as ls |
|
import specific_values as sv |
|
|
|
st.set_page_config(page_title="Curves with L-systems", page_icon="🖼️", layout="wide") |
|
|
|
|
|
@st.cache_data |
|
def load_result(axiom, mult_axiom, rules, rotation_angle, starting_angle, skipped, nb_iterations, coeff): |
|
""" |
|
Return the result of the L-system with the specified parameters |
|
|
|
:param axiom: |
|
:param mult_axiom: |
|
:param rules: |
|
:param rotation_angle: |
|
:param starting_angle: |
|
:param skipped: |
|
:param nb_iterations: |
|
:param coeff: |
|
:return: the result of the "L-System rendering" |
|
""" |
|
try: |
|
config = ls.Config(skipped=skipped) |
|
rules = rules.strip("; ") |
|
rules_list = [] |
|
|
|
if rules: |
|
for item in rules.split(";"): |
|
if ':' in item: |
|
splits = item.split(":") |
|
if len(splits) == 2 and splits[0].strip(): |
|
left = splits[0].strip() |
|
right = splits[1].strip() |
|
rules_list.append((left, right)) |
|
else: |
|
raise ValueError(f"Every rule must be correctly written ( {item} )") |
|
else: |
|
raise ValueError(f"Every non empty rule must include a column character ( {item} ) ") |
|
|
|
rls = ls.Lsystc(config, axiom * mult_axiom, rules_list, nbiter=nb_iterations, verbose=sv.verbose) |
|
rls.turtle(step=sv.step, angle=rotation_angle, angleinit=starting_angle, coeff=coeff, |
|
color_length=sv.color_length, color_map=sv.color_map) |
|
|
|
result = rls.render(sv.renderer, save_files=sv.save_files, show_more=sv.show_more, show_3d=sv.show_3d, |
|
return_type=sv.return_type) |
|
except ValueError as ex: |
|
st.warning(f"Please verify your parameters - {ex}") |
|
st.stop() |
|
except Exception as ex: |
|
st.warning("Please verify your parameters") |
|
if sv.verbose: |
|
logger.exception(f"Something went wrong : {ex}") |
|
st.stop() |
|
else: |
|
return result |
|
|
|
|
|
def write_specific(content): |
|
""" |
|
Write streamlit content |
|
|
|
:param content: streamlit content |
|
:return: None |
|
""" |
|
try: |
|
st.write(content) |
|
except StreamlitAPIException as exc: |
|
|
|
if sv.verbose: |
|
logger.error(exc) |
|
|
|
|
|
def on_change_selection(): |
|
""" |
|
Change the parameters when the starting example is changed |
|
|
|
:return: None |
|
""" |
|
current_selection = st.session_state.my_selection |
|
axiom, mult_axiom, rules, rotation_angle, starting_angle, nb_iter, skipped, coeff = examples_data[current_selection] |
|
st.session_state.my_axiom = axiom |
|
st.session_state.my_mult_axiom = mult_axiom |
|
st.session_state.my_rules = rules |
|
st.session_state.my_rotation_angle = rotation_angle |
|
st.session_state.my_starting_angle = starting_angle |
|
st.session_state.my_nb_iter = nb_iter |
|
st.session_state.my_skipped = skipped |
|
st.session_state.my_coeff = coeff |
|
sv.redraw_auto = True |
|
|
|
|
|
with open("curves_parameters.yaml", 'r', encoding='utf8') as f: |
|
curves_parameters = yaml.safe_load(f) |
|
|
|
EXAMPLES_DEFAULT = 0 |
|
examples_names = [] |
|
examples_data = {} |
|
for c_name, c_params in curves_parameters.items(): |
|
examples_names.append(c_name) |
|
c_axiom = c_params.get('axiom', '') |
|
c_axiom_multiplier = c_params.get('axiom_multiplier', 1) |
|
c_rules = c_params.get('rules', '') |
|
c_rotation_angle = c_params.get('rotation_angle', 90.0) |
|
c_starting_angle = c_params.get('starting_angle', 0) |
|
c_nb_iter = c_params.get('nb_iter', 1) |
|
c_skipped = c_params.get('skipped', '') |
|
c_coeff = c_params.get('coeff', 1.0) |
|
examples_data[c_name] = (c_axiom, c_axiom_multiplier, c_rules, |
|
c_rotation_angle, c_starting_angle, c_nb_iter, c_skipped, c_coeff) |
|
|
|
|
|
EXAMPLES_DEFAULT_name = examples_names[EXAMPLES_DEFAULT] |
|
def_axiom, def_mult_axiom, def_rules, def_rotation_angle, def_starting_angle, def_nb_iter, def_skipped, def_coeff = \ |
|
examples_data[EXAMPLES_DEFAULT_name] |
|
|
|
with st.sidebar: |
|
MD_INTRO = """ |
|
You have the flexibility to select a starting example and to change the parameters :sunglasses: |
|
""" |
|
|
|
st.markdown(MD_INTRO) |
|
|
|
input_selection = st.selectbox('Starting example', examples_names, |
|
index=EXAMPLES_DEFAULT, on_change=on_change_selection, key="my_selection") |
|
|
|
input_axiom = st.text_input('Starting axiom', def_axiom, key="my_axiom") |
|
input_mult_axiom = st.number_input('Multiplier for axiom', value=def_mult_axiom, min_value=1, key="my_mult_axiom") |
|
|
|
input_rules = st.text_input('Rules', def_rules, help="Example for 2 rules -> A: ABC ; B: CAB ; ", |
|
key="my_rules") |
|
input_rotation_angle = st.number_input('Angle of rotation', |
|
value=def_rotation_angle, min_value=1.0, max_value=360.0, step=1.0, |
|
format='%f', key="my_rotation_angle") |
|
input_starting_angle = st.number_input('Starting angle', |
|
value=def_starting_angle, min_value=0, max_value=360, |
|
format='%d', key="my_starting_angle") |
|
|
|
input_skipped = st.text_input('Skipped characters', def_skipped, key="my_skipped") |
|
|
|
input_coeff = st.number_input('Coefficient', |
|
value=def_coeff, format='%f', key="my_coeff") |
|
|
|
input_nb_iter = st.number_input('Number of iterations', |
|
value=def_nb_iter, min_value=1, max_value=15, format='%d', key="my_nb_iter") |
|
|
|
st.markdown("# Curves with L-systems") |
|
|
|
st.markdown("""**Click on "Draw" to display the curve**""") |
|
|
|
if st.button('Draw') or sv.redraw_auto or 'start' not in st.session_state: |
|
sv.redraw_auto = False |
|
st.session_state['start'] = True |
|
res = load_result(input_axiom, input_mult_axiom, input_rules, input_rotation_angle, input_starting_angle, |
|
input_skipped, input_nb_iter, input_coeff) |
|
|
|
if sv.return_type == 'image': |
|
write_specific(st.image(res, caption='Generated image')) |
|
else: |
|
if sv.renderer == 'matplot': |
|
|
|
|
|
fig_html = mpld3.fig_to_html(res) |
|
components.html(fig_html, height=600) |
|
elif sv.renderer == 'bokeh': |
|
st.bokeh_chart(res, use_container_width=True) |
|
elif sv.renderer == 'plotly': |
|
st.plotly_chart(res, use_container_width=True) |
|
|
|
st.markdown("---") |
|
st.markdown("More details on Lindenmayer systems here : [Wikipedia](https://en.wikipedia.org/wiki/L-system)") |
|
|