Spaces:
Sleeping
Sleeping
| import io | |
| import math | |
| import pandas as pd | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| from matplotlib.figure import Figure | |
| from matplotlib.patches import Circle | |
| import matplotlib as mpl | |
| from pypdf import PdfWriter | |
| import panel as pn | |
| # MARK: Functions | |
| class PANES: | |
| TEMPLATE = "Template" | |
| RAW_DATA = "Experiment raw data" | |
| READY_DATA = "Experiment data" | |
| PLATE_VIEWER = "Plate viewer" | |
| PAGE_VIEWER = "Page viewer" | |
| VERTICAL_PADDING = 4 | |
| CFO_SHOW_COORDINATES = "Show coordinates" | |
| CFO_SHOW_BOLD_FONT = "Bold font" | |
| def expand_position(row, col, discs_per_leaf): | |
| min_row = (row - 1) * discs_per_leaf + 1 | |
| max_row = min_row + discs_per_leaf | |
| return (min_row, max_row), col | |
| def is_valid_forbibden_position(fp): | |
| return fp is not None and fp[0] > 0 and fp[1] > 0 | |
| def is_forbibden_position(fp, r, c): | |
| return is_valid_forbibden_position(fp) and r == fp[0] and c == fp[1] | |
| def get_next_position( | |
| tray, row, col, row_count: int, col_count: int, forbidden_position: tuple | None | |
| ): | |
| if col == 0 and row == 0: | |
| col = 1 | |
| row = 1 | |
| if is_forbibden_position(forbidden_position, row, col): | |
| return get_next_position( | |
| tray, | |
| col, | |
| row, | |
| row_count=row_count, | |
| col_count=col_count, | |
| forbidden_position=forbidden_position, | |
| ) | |
| return tray, row, col | |
| if col < col_count: | |
| col += 1 | |
| else: | |
| col = 1 | |
| if row < row_count: | |
| row += 1 | |
| else: | |
| row = 1 | |
| tray += 1 | |
| if is_forbibden_position(forbidden_position, row, col): | |
| return get_next_position( | |
| tray, | |
| col, | |
| row, | |
| row_count=row_count, | |
| col_count=col_count, | |
| forbidden_position=forbidden_position, | |
| ) | |
| return tray, row, col | |
| def draw_tray( | |
| forbidden_position: tuple | None, | |
| row_count: int, | |
| col_count: int, | |
| discs_per_leaf: int, | |
| tray_size: tuple, | |
| row: int = 0, | |
| col: int = 0, | |
| text_data: np.ndarray | None = None, | |
| color_data: np.ndarray | None = None, | |
| fig: Figure | None = None, | |
| fontsize=14, | |
| plaque_index: str | None = None, | |
| print_coordinates: bool = False, | |
| print_index: bool = False, | |
| coord_bf: bool = False, | |
| coord_font_size: int = 10, | |
| leaf_size: int | None = None, | |
| ): | |
| t = np.zeros((row_count * discs_per_leaf, col_count)) | |
| if is_valid_forbibden_position(forbidden_position): | |
| t[ | |
| forbidden_position[0] - 1 : forbidden_position[0] - 1 + discs_per_leaf, | |
| forbidden_position[1] - 1, | |
| ] = 1 | |
| if col > 0 and row > 0: | |
| (min_row, max_row), col = expand_position(row, col, discs_per_leaf) | |
| t[min_row - 1 : max_row - 1, col - 1] = 2 | |
| had_fig = fig is not None | |
| if fig is None: | |
| fig = Figure(figsize=tuple(i / 2.54 for i in tray_size)) | |
| axii = fig.subplots(nrows=t.shape[0], ncols=t.shape[1]) | |
| left, width = 0, 1 | |
| bottom, height = 0, 1 | |
| right = left + width | |
| top = bottom + height | |
| if color_data is not None and color_data.size > 0: | |
| cmap = mpl.colormaps["cool"] | |
| colors = cmap(np.linspace(0, 1, np.nanmax(color_data).astype(int) + 1)) | |
| def is_valid(a, i, j): | |
| return a is not None and 0 <= i < a.shape[0] and 0 <= j < a.shape[1] | |
| leaf_index = 0 | |
| for i, line in enumerate(axii): | |
| for j, ax in enumerate(line): | |
| if t[i, j] != 1: | |
| leaf_index += 1 | |
| # Draw background | |
| if i == 0 and j == 0 and plaque_index is not None and t[i, j] == 1: | |
| ax.set_facecolor("xkcd:light grey") | |
| else: | |
| if t[i, j] == 1: | |
| ax.set_facecolor("xkcd:black") | |
| elif color_data is None: | |
| match t[i, j]: | |
| case 0: | |
| ax.set_facecolor("xkcd:white") | |
| case 2: | |
| ax.set_facecolor("xkcd:salmon") | |
| elif is_valid(color_data, i, j) and np.isnan(color_data[i, j]) != True: | |
| ax.set_facecolor(colors[int(color_data[i, j].astype(int))]) | |
| # Draw leafs | |
| if leaf_size is not None and leaf_size > 0 and t[i, j] != 1: | |
| ax.add_patch( | |
| Circle( | |
| xy=(0.5, 0.5), | |
| radius=leaf_size / 2, | |
| edgecolor="green", | |
| facecolor="lime", | |
| linewidth=1, | |
| ) | |
| ) | |
| # Write text | |
| if print_coordinates is True: | |
| ax.text( | |
| left + 0.02, | |
| top - 0.02, | |
| f"{chr(65 + i)}{j+1}", | |
| dict(size=coord_font_size), | |
| horizontalalignment="left", | |
| verticalalignment="top", | |
| fontweight="bold" if coord_bf is True else "normal", | |
| ) | |
| ax.text( | |
| right - 0.03, | |
| bottom + 0.05, | |
| f"{chr(65 + i)}{j+1}", | |
| dict(size=coord_font_size), | |
| horizontalalignment="right", | |
| verticalalignment="bottom", | |
| rotation=180, | |
| transform_rotates_text=True, | |
| fontweight="bold" if coord_bf is True else "normal", | |
| ) | |
| if print_index is True: | |
| ax.text( | |
| 0.5, | |
| 0.5, | |
| str(leaf_index), | |
| dict(size=fontsize), | |
| horizontalalignment="center", | |
| verticalalignment="center", | |
| transform=ax.transAxes, | |
| ) | |
| if i == 0 and j == 0 and plaque_index is not None and t[i, j] == 1: | |
| ax.set_facecolor("xkcd:light grey") | |
| ax.text( | |
| 0.5, | |
| 0.5, | |
| plaque_index, | |
| dict(size=fontsize), | |
| horizontalalignment="center", | |
| verticalalignment="center", | |
| ) | |
| if ( | |
| text_data is not None | |
| and is_valid(text_data, i, j) | |
| and isinstance(text_data[i, j], str) is True | |
| ): | |
| ax.text( | |
| 0.5, | |
| 0.5, | |
| text_data[i, j], | |
| dict(size=fontsize), | |
| horizontalalignment="center", | |
| verticalalignment="center", | |
| transform=ax.transAxes, | |
| ) | |
| ax.set_xticklabels([]) | |
| ax.set_yticklabels([]) | |
| ax.set_xticks([]) | |
| ax.set_yticks([]) | |
| if had_fig is False: | |
| fig.tight_layout(pad=0.2) | |
| return fig | |
| def draw_page( | |
| data: pd.DataFrame, | |
| figs_per_col: int, | |
| figs_per_row: int, | |
| forbibden_position: tuple, | |
| row_count: int, | |
| col_count: int, | |
| discs_per_leaf: int, | |
| orientation: str, | |
| font_size: int, | |
| page_index: int, | |
| ): | |
| main_fig = Figure( | |
| figsize=(21, 29.7) if orientation == "portrait" else (29.7, 21), | |
| layout="constrained", | |
| ) | |
| subfigs = main_fig.subfigures(figs_per_row, figs_per_col, wspace=0.07) | |
| start_tray = (figs_per_col * figs_per_row * (page_index - 1)) + 1 | |
| for i in range(figs_per_col * figs_per_row): | |
| if i >= data.plaque.max(): | |
| break | |
| current_fig = subfigs.flatten()[i] | |
| draw_tray( | |
| forbidden_position=( | |
| None | |
| if forbibden_position is None | |
| else (forbibden_position[0], forbibden_position[1]) | |
| ), | |
| row_count=row_count, | |
| col_count=col_count, | |
| discs_per_leaf=discs_per_leaf, | |
| tray_size=(row_count * discs_per_leaf, col_count), | |
| text_data=data[data.plaque == i + start_tray] | |
| .pivot(index="ligne", columns="colonne", values="Num_Plvt") | |
| .values, | |
| color_data=data[data.plaque == i + start_tray] | |
| .pivot(index="ligne", columns="colonne", values="group") | |
| .values, | |
| fontsize=font_size, | |
| fig=current_fig, | |
| plaque_index=f"P{i+start_tray}", | |
| ) | |
| if is_valid_forbibden_position(forbibden_position) is False: | |
| current_fig.suptitle(f"P{i+start_tray}", fontsize=font_size) | |
| if "experience" in data: | |
| main_fig.suptitle( | |
| f"{data.iloc[0].experience}, page {page_index}", fontsize=font_size * 1.5 | |
| ) | |
| return main_fig | |
| def prepare_experiment( | |
| raw_data: pd.DataFrame, | |
| row_count: int, | |
| col_count: int, | |
| discs_per_leaf: int, | |
| forbidden_position: tuple, | |
| control_blocks: int = 3, | |
| ): | |
| ctr_data = raw_data[raw_data.TYPE == "THD"].reset_index(drop=True) | |
| gen_data = raw_data[raw_data.TYPE == "G"].reset_index(drop=True) | |
| match control_blocks: | |
| case 0: | |
| all_data = gen_data | |
| case 1: | |
| all_data = pd.concat( | |
| [ | |
| ctr_data.sample(n=len(ctr_data), random_state=0).assign( | |
| group=lambda x: 1 | |
| ), | |
| gen_data, | |
| ] | |
| ) | |
| case _: | |
| len_chunks = math.ceil(len(gen_data) / (control_blocks - 1)) | |
| list_chunks = [ | |
| gen_data[i : i + len_chunks] | |
| for i in range(0, len(gen_data), len_chunks) | |
| ] | |
| all_data = ctr_data.sample(n=len(ctr_data), random_state=0).assign( | |
| group=lambda x: 1 | |
| ) | |
| for i, chunk in enumerate(list_chunks): | |
| all_data = pd.concat( | |
| [ | |
| all_data, | |
| chunk, | |
| ctr_data.sample(n=len(ctr_data), random_state=i).assign( | |
| group=lambda x: i + 2 | |
| ), | |
| ] | |
| ) | |
| tray, row, col = 1, 0, 0 | |
| out = [] | |
| for _, r in all_data.reset_index(drop=True).iterrows(): | |
| tray, row, col = get_next_position( | |
| tray=tray, | |
| row=row, | |
| col=col, | |
| row_count=row_count, | |
| col_count=col_count, | |
| forbidden_position=forbidden_position, | |
| ) | |
| (min_row, max_row), col = expand_position( | |
| row, col, discs_per_leaf=discs_per_leaf | |
| ) | |
| for i in range(min_row, max_row): | |
| out.append( | |
| dict(r) | |
| | { | |
| "plaque": tray, | |
| "ligne": i, | |
| "colonne": col, | |
| "alpha_line": chr(i + 64), | |
| } | |
| ) | |
| return pd.DataFrame(out) | |
| # MARK: Template | |
| ii_row_count = pn.widgets.IntInput( | |
| name="Row count", start=1, end=100, value=3, sizing_mode="stretch_width" | |
| ) | |
| ii_col_count = pn.widgets.IntInput( | |
| name="Column count", start=1, end=100, value=9, sizing_mode="stretch_width" | |
| ) | |
| ii_discs_per_leaf = pn.widgets.IntInput( | |
| name="Discs per leaf", start=1, end=100, value=3, sizing_mode="stretch_width" | |
| ) | |
| ii_forbibden_row = pn.widgets.IntInput( | |
| name="Row", start=0, end=100, value=1, sizing_mode="stretch_width" | |
| ) | |
| ii_forbibden_col = pn.widgets.IntInput( | |
| name="Column", start=0, end=100, value=1, sizing_mode="stretch_width" | |
| ) | |
| ii_template_width = pn.widgets.IntInput( | |
| name="Template width (in mm)", | |
| start=10, | |
| end=1000, | |
| value=215, | |
| sizing_mode="stretch_width", | |
| ) | |
| ii_template_height = pn.widgets.IntInput( | |
| name="Template height (in mm)", | |
| start=10, | |
| end=1000, | |
| value=215, | |
| sizing_mode="stretch_width", | |
| ) | |
| cbg_coordinates = pn.widgets.CheckBoxGroup( | |
| name="Coordiantes options", | |
| options=[CFO_SHOW_COORDINATES, CFO_SHOW_BOLD_FONT], | |
| value=[CFO_SHOW_COORDINATES], | |
| inline=False, | |
| ) | |
| ii_coordinate_font_size = pn.widgets.IntInput( | |
| name="Coordinates font size", | |
| start=1, | |
| end=100, | |
| value=11, | |
| sizing_mode="stretch_width", | |
| ) | |
| ii_leaf_size = pn.widgets.FloatInput( | |
| name="Leaf size", | |
| start=0, | |
| end=100, | |
| value=0, | |
| step=0.1, | |
| sizing_mode="stretch_width", | |
| ) | |
| dwn_template = pn.widgets.FileDownload( | |
| file="", | |
| filename="", | |
| label="Download template", | |
| name="", | |
| # sizing_mode="stretch_width", | |
| icon="file-download", | |
| button_type="primary", | |
| align="end", | |
| ) | |
| cd_template = pn.layout.Card( | |
| pn.Column( | |
| pn.Row(ii_row_count, ii_col_count), | |
| ii_discs_per_leaf, | |
| pn.layout.Divider(), | |
| pn.pane.Str("Forbidden position", margin=(0, 10, -10, 2), align="center"), | |
| pn.Row(ii_forbibden_row, ii_forbibden_col), | |
| pn.layout.Divider(), | |
| pn.Row(ii_template_width, ii_template_height), | |
| pn.layout.Divider(), | |
| pn.Row(cbg_coordinates, ii_coordinate_font_size), | |
| ii_leaf_size, | |
| pn.layout.Divider(), | |
| dwn_template, | |
| ), | |
| title="Template", | |
| collapsed=True, | |
| margin=(VERTICAL_PADDING, 0, VERTICAL_PADDING, 0), | |
| ) | |
| # MARK: Load experiment | |
| csv_separator = pn.widgets.Select( | |
| name="CSV separator", options=[";", ","], sizing_mode="stretch_width" | |
| ) | |
| ii_control_blocks = pn.widgets.IntInput( | |
| name="Control blocks", start=0, end=100, value=3, sizing_mode="stretch_width" | |
| ) | |
| fi_raw_exp = pn.widgets.FileInput(accept=".csv,.json", sizing_mode="stretch_width") | |
| cd_load_exp = pn.layout.Card( | |
| pn.Column(pn.Row(csv_separator, ii_control_blocks), fi_raw_exp), | |
| title="Load experiment", | |
| collapsed=False, | |
| margin=(VERTICAL_PADDING, 0, VERTICAL_PADDING, 0), | |
| ) | |
| # MARK: View plates | |
| ii_plate_number = pn.widgets.IntInput( | |
| name="Plate number", | |
| start=1, | |
| end=1, | |
| value=1, | |
| sizing_mode="stretch_width", | |
| ) | |
| ii_font_size = pn.widgets.IntInput( | |
| name="Font size", | |
| start=1, | |
| end=100, | |
| value=14, | |
| sizing_mode="stretch_width", | |
| ) | |
| fd_genrate_exp_plates = pn.widgets.FileDownload( | |
| name="", button_type="primary", filename="exp_plates.pdf", align="end" | |
| ) | |
| cd_view_plates = pn.layout.Card( | |
| pn.Column(pn.Row(ii_font_size, ii_plate_number), fd_genrate_exp_plates), | |
| title="View plates", | |
| collapsed=False, | |
| margin=(VERTICAL_PADDING, 0, VERTICAL_PADDING, 0), | |
| ) | |
| # MARK: Page viewer | |
| ii_figs_per_col = pn.widgets.IntInput( | |
| name="Plates per column", start=1, end=100, value=3, sizing_mode="stretch_width" | |
| ) | |
| ii_figs_per_row = pn.widgets.IntInput( | |
| name="Plates per row", start=1, end=100, value=3, sizing_mode="stretch_width" | |
| ) | |
| sel_orientation = pn.widgets.Select( | |
| name="Page orientation", | |
| options=["Landscape", "Portrait"], | |
| sizing_mode="stretch_width", | |
| ) | |
| ii_page_font_size = pn.widgets.IntInput( | |
| name="Page font size", | |
| start=1, | |
| end=100, | |
| value=14, | |
| sizing_mode="stretch_width", | |
| ) | |
| isl_page_index = pn.widgets.IntInput( | |
| name="Page index", start=1, end=100, value=1, sizing_mode="stretch_width" | |
| ) | |
| bt_generate_page = pn.widgets.Button( | |
| name="View page", button_type="primary", align="center" | |
| ) | |
| fd_genrate_exp_helper = pn.widgets.FileDownload( | |
| name="", | |
| button_type="primary", | |
| filename="exp_helper.pdf", | |
| align="center", | |
| sizing_mode="stretch_width", | |
| ) | |
| cd_view_pages = pn.layout.Card( | |
| pn.Column( | |
| pn.Row(ii_figs_per_row, ii_figs_per_col), | |
| isl_page_index, | |
| pn.Row(sel_orientation, ii_page_font_size), | |
| pn.Row(bt_generate_page, fd_genrate_exp_helper), | |
| ), | |
| title="View pages", | |
| collapsed=False, | |
| margin=(VERTICAL_PADDING, 0, VERTICAL_PADDING, 0), | |
| ) | |
| # MARK: Main form | |
| rbg_active = pn.widgets.RadioButtonGroup( | |
| name="", | |
| options=[ | |
| PANES.TEMPLATE, | |
| PANES.RAW_DATA, | |
| PANES.READY_DATA, | |
| PANES.PLATE_VIEWER, | |
| PANES.PAGE_VIEWER, | |
| ], | |
| value=PANES.TEMPLATE, | |
| button_type="primary", | |
| button_style="outline", | |
| sizing_mode="stretch_width", | |
| ) | |
| plt_template = pn.pane.Matplotlib(align="center", sizing_mode="stretch_height") | |
| tb_raw_experiment = pn.widgets.Tabulator( | |
| value=pd.DataFrame(), pagination="local", page_size=20, sizing_mode="stretch_width" | |
| ) | |
| tb_experiment = pn.widgets.Tabulator( | |
| value=pd.DataFrame(), pagination="local", page_size=20, sizing_mode="stretch_width" | |
| ) | |
| plt_plate = pn.pane.Matplotlib(align="center", sizing_mode="stretch_height") | |
| plt_page = pn.pane.Matplotlib(align="center", sizing_mode="stretch_height") | |
| ph_main = pn.pane.Placeholder(object=plt_template) | |
| # MARK: Callbacks | |
| def update_experiment(): | |
| tb_experiment.value = prepare_experiment( | |
| raw_data=tb_raw_experiment.value, | |
| row_count=ii_row_count.value, | |
| col_count=ii_col_count.value, | |
| discs_per_leaf=ii_discs_per_leaf.value, | |
| forbidden_position=(ii_forbibden_row.value, ii_forbibden_col.value), | |
| control_blocks=ii_control_blocks.value, | |
| ) | |
| ii_plate_number.end = int(tb_experiment.value.plaque.max()) | |
| ii_plate_number.value = 1 | |
| plt_plate.object = update_tray(data=tb_experiment.value) | |
| def update_tray(data: pd.DataFrame | None = None, plate_number: int | None = None): | |
| if data is not None: | |
| p_number = ( | |
| data.plaque == ii_plate_number.value | |
| if plate_number is None | |
| else plate_number | |
| ) | |
| text_data = ( | |
| data[data.plaque == p_number] | |
| .pivot(index="ligne", columns="colonne", values="Num_Plvt") | |
| .values | |
| ) | |
| color_data = ( | |
| data[data.plaque == p_number] | |
| .pivot(index="ligne", columns="colonne", values="group") | |
| .values | |
| ) | |
| else: | |
| text_data = None | |
| color_data = None | |
| return draw_tray( | |
| forbidden_position=(ii_forbibden_row.value, ii_forbibden_col.value), | |
| row_count=ii_row_count.value, | |
| col_count=ii_col_count.value, | |
| discs_per_leaf=ii_discs_per_leaf.value, | |
| tray_size=(ii_template_width.value / 10, ii_template_height.value / 10), | |
| text_data=text_data, | |
| color_data=color_data, | |
| fontsize=ii_font_size.value, | |
| coord_font_size=ii_coordinate_font_size.value, | |
| print_coordinates=CFO_SHOW_COORDINATES in cbg_coordinates.value, | |
| coord_bf=CFO_SHOW_BOLD_FONT in cbg_coordinates.value, | |
| leaf_size=ii_leaf_size.value, | |
| ) | |
| def on_exp_plates_requested(data): | |
| merger = PdfWriter() | |
| for i in sorted(data.plaque.unique()): | |
| fig = update_tray(data, plate_number=int(i)) | |
| s_buf = io.BytesIO() | |
| fig.savefig(s_buf, bbox_inches="tight", pad_inches=0, format="pdf") | |
| s_buf.seek(0) | |
| merger.append(s_buf) | |
| out_buf = io.BytesIO() | |
| merger.write(out_buf) | |
| out_buf.seek(0) | |
| return out_buf | |
| fd_genrate_exp_plates.callback = pn.bind(on_exp_plates_requested, tb_experiment) | |
| def on_exp_helper_requested(data): | |
| merger = PdfWriter() | |
| figs_per_col = ii_figs_per_col.value | |
| figs_per_row = ii_figs_per_row.value | |
| page_count = data.plaque.max() // (figs_per_row * figs_per_col) + 1 | |
| for i in range(page_count): | |
| fig = draw_page( | |
| data=data, | |
| figs_per_col=figs_per_col, | |
| figs_per_row=figs_per_row, | |
| forbibden_position=(ii_forbibden_row.value, ii_forbibden_col.value), | |
| row_count=ii_row_count.value, | |
| col_count=ii_col_count.value, | |
| discs_per_leaf=ii_discs_per_leaf.value, | |
| orientation=sel_orientation.value.lower(), | |
| font_size=ii_page_font_size.value, | |
| page_index=i + 1, | |
| ) | |
| s_buf = io.BytesIO() | |
| fig.savefig(s_buf, bbox_inches="tight", pad_inches=0, format="pdf") | |
| s_buf.seek(0) | |
| merger.append(s_buf) | |
| out_buf = io.BytesIO() | |
| merger.write(out_buf) | |
| out_buf.seek(0) | |
| return out_buf | |
| fd_genrate_exp_helper.callback = pn.bind(on_exp_helper_requested, tb_experiment) | |
| def on_plate_number_changed(plate_number): | |
| plt_plate.object = update_tray(data=tb_experiment.value) | |
| def on_plate_number_changed(font_size): | |
| plt_plate.object = update_tray(data=tb_experiment.value) | |
| def on_template_changed( | |
| row_count, | |
| col_count, | |
| discs_per_leaf, | |
| forbibden_row, | |
| forbibden_column, | |
| template_width, | |
| template_height, | |
| show_coordinates, | |
| coordinate_font_size, | |
| leaf_size, | |
| control_blocks, | |
| ): | |
| fig = update_tray() | |
| s_buf = io.BytesIO() | |
| fig.savefig(s_buf, bbox_inches="tight", pad_inches=0, format="pdf") | |
| s_buf.seek(0) | |
| dwn_template.filename = ( | |
| f"[R{row_count}][C{col_count}][DPL{discs_per_leaf}]_template.pdf" | |
| ) | |
| dwn_template.file = s_buf | |
| plt_template.object = fig | |
| if len(tb_raw_experiment.value) > 0: | |
| update_experiment() | |
| def on_file_loaded(value): | |
| if not value or not isinstance(value, bytes): | |
| return pd.DataFrame() | |
| string_io = io.StringIO(value.decode("utf8")) | |
| ret = pd.read_csv(string_io, sep=csv_separator.value) | |
| # ret = pd.concat([ret.sample(n=len(ret)) for _ in range(60)]).reset_index(drop=True) | |
| tb_raw_experiment.value = ret | |
| update_experiment() | |
| fd_genrate_exp_plates.file = "exp_plates.pdf" | |
| fd_genrate_exp_helper.file = "exp_helper.pdf" | |
| rbg_active.value = PANES.READY_DATA | |
| def on_active_pane_changed(rbg_value): | |
| match rbg_value: | |
| case PANES.TEMPLATE: | |
| ph_main.object = plt_template | |
| cd_template.collapsed = False | |
| case PANES.RAW_DATA: | |
| ph_main.object = tb_raw_experiment | |
| case PANES.READY_DATA: | |
| ph_main.object = tb_experiment | |
| case PANES.PLATE_VIEWER: | |
| ph_main.object = plt_plate | |
| cd_view_plates.collapsed = False | |
| case PANES.PAGE_VIEWER: | |
| ph_main.object = plt_page | |
| cd_view_pages.collapsed = False | |
| def on_page_requested(event): | |
| if not event: | |
| return | |
| rbg_active.value = PANES.PAGE_VIEWER | |
| plt_page.object = draw_page( | |
| data=tb_experiment.value, | |
| figs_per_col=ii_figs_per_col.value, | |
| figs_per_row=ii_figs_per_row.value, | |
| forbibden_position=(ii_forbibden_row.value, ii_forbibden_col.value), | |
| row_count=ii_row_count.value, | |
| col_count=ii_col_count.value, | |
| discs_per_leaf=ii_discs_per_leaf.value, | |
| orientation=sel_orientation.value.lower(), | |
| font_size=ii_page_font_size.value, | |
| page_index=isl_page_index.value, | |
| ) | |
| pn.bind(on_page_requested, bt_generate_page, watch=True) | |
| on_template_changed( | |
| *[ | |
| p.value | |
| for p in [ | |
| ii_row_count, | |
| ii_col_count, | |
| ii_discs_per_leaf, | |
| ii_forbibden_row, | |
| ii_forbibden_col, | |
| ii_template_width, | |
| ii_template_height, | |
| cbg_coordinates, | |
| ii_coordinate_font_size, | |
| ii_leaf_size, | |
| ii_control_blocks, | |
| ] | |
| ] | |
| ) | |
| # MARK: Layout | |
| pn.extension("tabulator", "ipywidgets") | |
| template = pn.template.BootstrapTemplate(title="Vitis Experiment Builder") | |
| template.sidebar.append( | |
| pn.Column( | |
| cd_template, | |
| cd_load_exp, | |
| cd_view_plates, | |
| cd_view_pages, | |
| ) | |
| ) | |
| template.main.append(pn.Column(rbg_active, ph_main)) | |
| template.servable() | |