-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.json
1 lines (1 loc) · 33.3 KB
/
app.json
1
[{"name": "app.py", "content": "import matplotlib\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom shiny.express import input, output, render, ui\n\n# Thelen muscle model with full calculations\ndef thelen_muscle(onoff, freq, excursion, L0, F0, Vx, af, tau_a, tau_d):\n try:\n onset = onoff[0] / 100\n offset = onoff[1] / 100\n excursion = excursion / 1000 # Convert mm to meters\n tau_a = tau_a / 1000 # Convert to seconds\n tau_d = tau_d / 1000 # Convert to seconds\n\n act_pct = 1\n onset_time = onset / freq\n offset_time = offset / freq\n dt = 0.001 / freq # Time step\n V0 = Vx * L0\n penn0 = 0.087\n k_shape = 0.5\n w = L0 * np.sin(penn0)\n\n # Time and cycle percentage\n t = np.arange(0, 1.25 / freq, dt)\n cycle_pct = t * freq\n\n # Position\n position = excursion * np.sin(2 * np.pi * freq * t)\n position_mm = position * 1000\n\n # Excitation and Activation Dynamics\n excitation = np.where((t >= onset_time) & (t <= offset_time), 1 * act_pct, 0)\n da_dt = np.zeros(len(t))\n activation = np.zeros(len(t))\n\n for i in range(1, len(t)):\n if excitation[i - 1] >= activation[i - 1]:\n da_dt[i] = (excitation[i - 1] - activation[i - 1]) / tau_a\n else:\n da_dt[i] = (excitation[i - 1] - activation[i - 1]) / tau_d\n activation[i] = activation[i - 1] + da_dt[i] * dt\n\n # Pennation and muscle length\n penn = np.arcsin(w / (position + L0))\n muscle_length = position / np.cos(penn0) + L0\n muscle_length_norm = muscle_length / L0\n\n # Velocity\n v = (-2 * np.pi * freq * excursion * np.cos(2 * np.pi * freq * t)) / np.cos(penn)\n v_norm = v / (V0 * ((Vx / 2) + (Vx / 2) * activation) / Vx)\n\n # Force-Length relationship\n fl_norm = np.exp(-((muscle_length_norm - 1) ** 2) / k_shape)\n\n # Force-Velocity relationship\n fv_norm = np.where(v > (V0 * ((Vx / 2) + (Vx / 2))), 0,\n np.where(v_norm > 0, (1 - v_norm) / (1 + v_norm / af),\n (1.8 - (0.8 * (1 + v / V0)) / (1 - 7.56 * 0.21 * v / V0))))\n\n # Contractile element force\n force_ce = activation * F0 * fl_norm * fv_norm\n\n # Total force\n force_total = force_ce\n\n # Work and Power calculations\n work = force_total * v * dt\n power = force_total * v\n work_actual = np.sum(work)\n work_positive = np.sum(work[work > 0])\n work_negative = np.sum(work[work < 0])\n power_actual = np.mean(power[(t >= onset_time) & (t <= onset_time + 1)])\n\n # Data to return\n sim_data = pd.DataFrame({\n 't': t,\n 'cycle_pct': cycle_pct,\n 'position': position,\n 'position_mm': position_mm,\n 'velocity': v,\n 'force_total': force_total,\n 'work': work,\n 'power': power,\n 'excitation': excitation,\n 'activation': activation\n })\n\n return {\n 'sim_data': sim_data,\n 'work_actual': work_actual,\n 'work_positive': work_positive,\n 'work_negative': work_negative,\n 'power_actual': power_actual\n }\n except Exception as e:\n print(f\"Error in thelen_muscle: {e}\")\n return None\n\n# Optimization function for the Thelen model\ndef thelen_muscle_opt(freq, excursion, L0, F0, Vx, af, tau_a, tau_d):\n onset_values = np.arange(20, 26, 1)\n offset_values = np.arange(26, 76, 1)\n\n best_onset = None\n best_offset = None\n max_power = -np.inf\n\n for onset in onset_values:\n for offset in offset_values:\n sim_results = thelen_muscle([onset, offset], freq, excursion, L0, F0, Vx, af, tau_a, tau_d)\n if sim_results is None:\n continue\n\n current_power = sim_results['power_actual']\n\n if current_power > max_power:\n best_onset = onset\n best_offset = offset\n max_power = current_power\n\n if best_onset is not None and best_offset is not None:\n optimized_results = thelen_muscle([best_onset, best_offset], freq, excursion, L0, F0, Vx, af, tau_a, tau_d)\n return optimized_results, best_onset, best_offset, max_power\n return None, None, None, None\n\n# Define the run_simulation function with theoretical results\ndef run_simulation():\n # Simulated muscle parameters\n muscle_params = {\n \"onoff\": [input.onset(), input.offset()],\n \"freq\": input.cycle_freq(),\n \"excursion\": input.excursion(),\n \"L0\": input.length_optimal(),\n \"F0\": input.max_isometric_force(),\n \"Vx\": input.max_velocity(),\n \"af\": input.force_velocity_curvature(),\n \"tau_a\": input.activation_time(),\n \"tau_d\": input.deactivation_time(),\n }\n \n # Calculate simulated results\n if input.optimize():\n sim_results, _, _, _ = thelen_muscle_opt(\n input.cycle_freq(), input.excursion(), input.length_optimal(),\n input.max_isometric_force(), input.max_velocity(),\n input.force_velocity_curvature(), input.activation_time(),\n input.deactivation_time()\n )\n else:\n sim_results = thelen_muscle(**muscle_params)\n \n # Theoretical muscle parameters (instantaneous activation/deactivation and no onoff)\n theoretical_params = muscle_params.copy()\n theoretical_params['onoff'] = [25, 75] # No onset or offset\n theoretical_params['tau_a'] = 0.5 # No activation time\n theoretical_params['tau_d'] = 1 # No deactivation time\n \n # Calculate theoretical results with zero onset/offset and instantaneous activation/deactivation\n theoretical_results = thelen_muscle(**theoretical_params)\n \n return sim_results, theoretical_results\n\n# Define the UI layout\nwith ui.sidebar():\n ui.input_slider(\"onset\", \"Onset (% of cycle)\", min=20, max=25, value=22),\n ui.input_slider(\"offset\", \"Offset (% of cycle)\", min=26, max=100, value=66),\n ui.input_slider(\"excursion\", \"Excursion amplitude (mm)\", min=1, max=50, value=20),\n ui.input_slider(\"cycle_freq\", \"Cycle frequency (Hz)\", min=0.5, max=4.5, value=2.0),\n ui.input_numeric(\"length_optimal\", \"Length optimal (m)\", value=0.084),\n ui.input_numeric(\"max_isometric_force\", \"Max isometric force (N)\", value=1871),\n ui.input_numeric(\"max_velocity\", \"Max velocity (fiber lengths/s)\", value=10),\n ui.input_numeric(\"force_velocity_curvature\", \"Force-velocity curvature\", value=0.30),\n ui.input_numeric(\"activation_time\", \"Activation time (ms)\", value=10),\n ui.input_numeric(\"deactivation_time\", \"Deactivation time (ms)\", value=40),\n ui.input_checkbox(\"optimize\", \"Optimize Onset/Offset\", value=False)\n\n\nwith ui.card():\n with ui.navset_bar(title=\"Virtual Muscle Lab\"):\n with ui.nav_panel(title=\"Graphs\"):\n @render.plot\n def combined_graphs():\n results = run_simulation()\n sim_results = results[0] # First item in the tuple is sim_results\n theoretical_results = results[1] # Second item is theoretical_results\n if sim_results is None or theoretical_results is None:\n print(\"Simulation failed: one or both result sets are None\")\n return\n\n # Create a 2x2 grid of subplots\n fig, axs = plt.subplots(2, 2, figsize=(12, 10)) # 2 rows, 2 columns\n\n # Top-left: Force vs. % of Cycle\n force_total_sim = sim_results['sim_data']['force_total']\n cycle_pct_sim = sim_results['sim_data']['cycle_pct']\n \n force_total_theoretical = theoretical_results['sim_data']['force_total']\n cycle_pct_theoretical = theoretical_results['sim_data']['cycle_pct']\n \n axs[0, 0].plot(cycle_pct_sim, force_total_sim, label='Simulated Force')\n axs[0, 0].plot(cycle_pct_theoretical, force_total_theoretical, label='Theoretical Force', linestyle='--')\n axs[0, 0].set_title(\"Force vs. % of Cycle\")\n axs[0, 0].set_xlabel(\"% of Cycle\")\n axs[0, 0].set_ylabel(\"Force (N)\")\n \n\n # Top-right: Velocity vs. % of Cycle\n velocity_sim = sim_results['sim_data']['velocity']\n velocity_theoretical = theoretical_results['sim_data']['velocity']\n \n axs[0, 1].plot(cycle_pct_sim, velocity_sim, color=\"green\", label='Simulated Velocity')\n axs[0, 1].plot(cycle_pct_theoretical, velocity_theoretical, color=\"lightgreen\", linestyle='--', label='Theoretical Velocity')\n axs[0, 1].set_title(\"Velocity vs. % of Cycle\")\n axs[0, 1].set_xlabel(\"% of Cycle\")\n axs[0, 1].set_ylabel(\"Velocity (m/s)\")\n \n\n # Bottom-left: Position vs. % of Cycle\n position_sim = sim_results['sim_data']['position']\n position_theoretical = theoretical_results['sim_data']['position']\n \n axs[1, 0].plot(cycle_pct_sim, position_sim, color=\"orange\", label='Simulated Position')\n axs[1, 0].plot(cycle_pct_theoretical, position_theoretical, color=\"darkorange\", linestyle='--', label='Theoretical Position')\n axs[1, 0].set_title(\"Position vs. % of Cycle\")\n axs[1, 0].set_xlabel(\"% of Cycle\")\n axs[1, 0].set_ylabel(\"Position (m)\")\n \n\n # Bottom-right: Power vs. % of Cycle\n power_sim = sim_results['sim_data']['power']\n power_theoretical = theoretical_results['sim_data']['power']\n \n axs[1, 1].plot(cycle_pct_sim, power_sim, color=\"red\", label='Simulated Power')\n axs[1, 1].plot(cycle_pct_theoretical, power_theoretical, color=\"lightcoral\", linestyle='--', label='Theoretical Power')\n axs[1, 1].set_title(\"Power vs. % of Cycle\")\n axs[1, 1].set_xlabel(\"% of Cycle\")\n axs[1, 1].set_ylabel(\"Power (W)\")\n \n\n # Adjust layout\n fig.tight_layout()\n return fig\n\n\n @render.plot\n def work_loop1():\n results = run_simulation()\n sim_results = results[0] # First item in the tuple is sim_results\n theoretical_results = results[1] # Second item is theoretical_results\n if sim_results is None or theoretical_results is None:\n print(\"Simulation failed: one or both result sets are None\")\n return\n\n fig, ax = plt.subplots()\n\n # Extract force and position data for the work-loop graph\n force_total_sim = sim_results['sim_data']['force_total']\n position_sim = sim_results['sim_data']['position']\n \n force_total_theoretical = theoretical_results['sim_data']['force_total']\n position_theoretical = theoretical_results['sim_data']['position']\n\n # Plot force vs. position (excursion)\n ax.plot(position_sim, force_total_sim, label=\"Simulated Work Loop\")\n ax.plot(position_theoretical, force_total_theoretical, label=\"Theoretical Work Loop\", linestyle='--')\n\n ax.set_title(\"Work Loop (Force vs. Excursion)\")\n ax.set_xlabel(\"Excursion (m)\")\n ax.set_ylabel(\"Force (N)\")\n ax.legend()\n\n return fig\n\n with ui.nav_panel(title=\"Graphs2\"):\n \n# Define Server logic and plotting\n \n @render.plot\n def force_cycle_with_theoretical():\n results = run_simulation()\n sim_results = results[0] # First item in the tuple is sim_results\n theoretical_results = results[1] # Second item is theoretical_results\n\n if sim_results is None or theoretical_results is None:\n print(\"Simulation failed: one or both result sets are None\")\n return\n\n # Create the plot\n fig, ax = plt.subplots()\n\n # Plot Simulated Force vs. % of Cycle\n ax.plot(sim_results['sim_data']['cycle_pct'], sim_results['sim_data']['force_total'], label='Simulated Force', color='blue')\n\n # Plot Theoretical Force vs. % of Cycle\n ax.plot(theoretical_results['sim_data']['cycle_pct'], theoretical_results['sim_data']['force_total'], label='Theoretical Force', color='orange')\n\n # Add labels and legend\n ax.set_title(\"Force vs. % of Cycle (Simulated vs. Theoretical)\")\n ax.set_xlabel(\"% of Cycle\")\n ax.set_ylabel(\"Force (N)\")\n ax.legend()\n\n return fig\n\n\n @render.plot\n def velocity_cycle():\n results = run_simulation()\n sim_results = results[0]\n theoretical_results = results[1]\n\n if sim_results is None or theoretical_results is None:\n print(\"Simulation failed: one or both result sets are None\")\n return\n\n # Create the plot\n fig, ax = plt.subplots()\n\n # Plot Simulated Velocity vs. % of Cycle\n ax.plot(sim_results['sim_data']['cycle_pct'], sim_results['sim_data']['velocity'], label='Simulated Velocity', color='green')\n\n # Plot Theoretical Velocity vs. % of Cycle\n ax.plot(theoretical_results['sim_data']['cycle_pct'], theoretical_results['sim_data']['velocity'], label='Theoretical Velocity', color='lightgreen')\n\n # Add labels and legend\n ax.set_title(\"Velocity vs. % of Cycle (Simulated vs. Theoretical)\")\n ax.set_xlabel(\"% of Cycle\")\n ax.set_ylabel(\"Velocity (m/s)\")\n ax.legend()\n\n return fig\n\n\n @render.plot\n def position_cycle():\n results = run_simulation()\n sim_results = results[0]\n theoretical_results = results[1]\n\n if sim_results is None or theoretical_results is None:\n print(\"Simulation failed: one or both result sets are None\")\n return\n\n # Create the plot\n fig, ax = plt.subplots()\n\n # Plot Simulated Position vs. % of Cycle\n ax.plot(sim_results['sim_data']['cycle_pct'], sim_results['sim_data']['position'], label='Simulated Position', color='orange')\n\n # Plot Theoretical Position vs. % of Cycle\n ax.plot(theoretical_results['sim_data']['cycle_pct'], theoretical_results['sim_data']['position'], label='Theoretical Position', color='darkorange')\n\n # Add labels and legend\n ax.set_title(\"Position vs. % of Cycle (Simulated vs. Theoretical)\")\n ax.set_xlabel(\"% of Cycle\")\n ax.set_ylabel(\"Position (m)\")\n ax.legend()\n \n return fig\n\n\n @render.plot\n def power_cycle():\n results = run_simulation()\n sim_results = results[0]\n theoretical_results = results[1]\n\n if sim_results is None or theoretical_results is None:\n print(\"Simulation failed: one or both result sets are None\")\n return\n\n # Create the plot\n fig, ax = plt.subplots()\n\n # Plot Simulated Power vs. % of Cycle\n ax.plot(sim_results['sim_data']['cycle_pct'], sim_results['sim_data']['power'], label='Simulated Power', color='red')\n\n # Plot Theoretical Power vs. % of Cycle\n ax.plot(theoretical_results['sim_data']['cycle_pct'], theoretical_results['sim_data']['power'], label='Theoretical Power', color='lightcoral')\n\n # Add labels and legend\n ax.set_title(\"Power vs. % of Cycle (Simulated vs. Theoretical)\")\n ax.set_xlabel(\"% of Cycle\")\n ax.set_ylabel(\"Power (W)\")\n ax.legend()\n\n return fig\n\n\n @render.plot\n def work_loop():\n results = run_simulation()\n sim_results = results[0]\n theoretical_results = results[1]\n\n if sim_results is None or theoretical_results is None:\n print(\"Simulation failed: one or both result sets are None\")\n return\n\n # Create the plot\n fig, ax = plt.subplots()\n\n # Extract force and position data for the work-loop graph\n force_total_sim = sim_results['sim_data']['force_total']\n position_sim = sim_results['sim_data']['position']\n \n force_total_theoretical = theoretical_results['sim_data']['force_total']\n position_theoretical = theoretical_results['sim_data']['position']\n\n # Plot force vs. position (excursion) for both simulated and theoretical\n ax.plot(position_sim, force_total_sim, label=\"Simulated Work Loop\", color='blue')\n ax.plot(position_theoretical, force_total_theoretical, label=\"Theoretical Work Loop\", linestyle='--', color='orange')\n\n # Add labels and legend\n ax.set_title(\"Work Loop (Force vs. Excursion)\")\n ax.set_xlabel(\"Excursion (m)\")\n ax.set_ylabel(\"Force (N)\")\n ax.legend()\n\n return fig\n\n \n@render.table\ndef results():\n # Unpack the tuple into sim_results and theoretical_results\n results = run_simulation()\n sim_results = results[0] # First item in the tuple is sim_results\n theoretical_results = results[1] # Second item is theoretical_results\n\n if sim_results is None or theoretical_results is None:\n print(\"Simulation failed: one or both result sets are None\")\n return pd.DataFrame()\n\n # Create a DataFrame with both simulated and theoretical results\n results_df = pd.DataFrame({\n \"Metric\": [\"Total Work\", \"Positive Work\", \"Negative Work\", \"Power\"],\n \"Simulated Results\": [\n sim_results['work_actual'],\n sim_results['work_positive'],\n sim_results['work_negative'],\n sim_results['power_actual']\n ],\n \"Theoretical Results\": [\n theoretical_results['work_actual'],\n theoretical_results['work_positive'],\n theoretical_results['work_negative'],\n theoretical_results['power_actual']\n ]\n })\n\n return results_df\n # New function to render the optimized onset/offset table\n@render.table\ndef optimized_onset_offset():\n # Show optimized onset/offset only if the optimize checkbox is selected\n if input.optimize():\n # Call run_simulation and assume it returns the optimized onset and offset as well\n optimized_results = thelen_muscle_opt(input.cycle_freq(), input.excursion(), input.length_optimal(),\n input.max_isometric_force(), input.max_velocity(),\n input.force_velocity_curvature(), input.activation_time(), input.deactivation_time())\n if optimized_results is None:\n return pd.DataFrame()\n\n # Extract optimized onset and offset values from the optimization function\n _, optimized_onset, optimized_offset, _ = optimized_results\n\n # Create a DataFrame for the optimized values\n optimization_df = pd.DataFrame({\n \"Parameter\": [\"Optimized Onset\", \"Optimized Offset\"],\n \"Value\": [optimized_onset, optimized_offset]\n })\n\n return optimization_df\n else:\n # If optimization is not selected, return an empty DataFrame\n return pd.DataFrame()\n", "type": "text"}, {"name": "app copy.py", "content": "import matplotlib\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom shiny.express import input, output, render, ui\n\n# Thelen muscle model with full calculations\ndef thelen_muscle(onoff, freq, excursion, L0, F0, Vx, af, tau_a, tau_d):\n try:\n onset = onoff[0] / 100\n offset = onoff[1] / 100\n excursion = excursion / 1000 # Convert mm to meters\n tau_a = tau_a / 1000 # Convert to seconds\n tau_d = tau_d / 1000 # Convert to seconds\n\n act_pct = 1\n onset_time = onset / freq\n offset_time = offset / freq\n dt = 0.001 / freq # Time step\n V0 = Vx * L0\n penn0 = 0.087\n k_shape = 0.5\n w = L0 * np.sin(penn0)\n\n # Time and cycle percentage\n t = np.arange(0, 1.25 / freq, dt)\n cycle_pct = t * freq\n\n # Position\n position = excursion * np.sin(2 * np.pi * freq * t)\n position_mm = position * 1000\n\n # Excitation and Activation Dynamics\n excitation = np.where((t >= onset_time) & (t <= offset_time), 1 * act_pct, 0)\n da_dt = np.zeros(len(t))\n activation = np.zeros(len(t))\n\n for i in range(1, len(t)):\n if excitation[i - 1] >= activation[i - 1]:\n da_dt[i] = (excitation[i - 1] - activation[i - 1]) / tau_a\n else:\n da_dt[i] = (excitation[i - 1] - activation[i - 1]) / tau_d\n activation[i] = activation[i - 1] + da_dt[i] * dt\n\n # Pennation and muscle length\n penn = np.arcsin(w / (position + L0))\n muscle_length = position / np.cos(penn0) + L0\n muscle_length_norm = muscle_length / L0\n\n # Velocity\n v = (-2 * np.pi * freq * excursion * np.cos(2 * np.pi * freq * t)) / np.cos(penn)\n v_norm = v / (V0 * ((Vx / 2) + (Vx / 2) * activation) / Vx)\n\n # Force-Length relationship\n fl_norm = np.exp(-((muscle_length_norm - 1) ** 2) / k_shape)\n\n # Force-Velocity relationship\n fv_norm = np.where(v > (V0 * ((Vx / 2) + (Vx / 2))), 0,\n np.where(v_norm > 0, (1 - v_norm) / (1 + v_norm / af),\n (1.8 - (0.8 * (1 + v / V0)) / (1 - 7.56 * 0.21 * v / V0))))\n\n # Contractile element force\n force_ce = activation * F0 * fl_norm * fv_norm\n\n # Total force\n force_total = force_ce\n\n # Work and Power calculations\n work = force_total * v * dt\n power = force_total * v\n work_actual = np.sum(work)\n work_positive = np.sum(work[work > 0])\n work_negative = np.sum(work[work < 0])\n power_actual = np.mean(power[(t >= onset_time) & (t <= onset_time + 1)])\n\n # Data to return\n sim_data = pd.DataFrame({\n 't': t,\n 'cycle_pct': cycle_pct,\n 'position': position,\n 'position_mm': position_mm,\n 'velocity': v,\n 'force_total': force_total,\n 'work': work,\n 'power': power,\n 'excitation': excitation,\n 'activation': activation\n })\n\n return {\n 'sim_data': sim_data,\n 'work_actual': work_actual,\n 'work_positive': work_positive,\n 'work_negative': work_negative,\n 'power_actual': power_actual\n }\n except Exception as e:\n print(f\"Error in thelen_muscle: {e}\")\n return None\n\n# Optimization function for the Thelen model\ndef thelen_muscle_opt(freq, excursion, L0, F0, Vx, af, tau_a, tau_d):\n onset_values = np.arange(20, 26, 1)\n offset_values = np.arange(26, 76, 1)\n\n best_onset = None\n best_offset = None\n max_power = -np.inf\n\n for onset in onset_values:\n for offset in offset_values:\n sim_results = thelen_muscle([onset, offset], freq, excursion, L0, F0, Vx, af, tau_a, tau_d)\n if sim_results is None:\n continue\n\n current_power = sim_results['power_actual']\n\n if current_power > max_power:\n best_onset = onset\n best_offset = offset\n max_power = current_power\n\n if best_onset is not None and best_offset is not None:\n optimized_results = thelen_muscle([best_onset, best_offset], freq, excursion, L0, F0, Vx, af, tau_a, tau_d)\n return optimized_results, best_onset, best_offset, max_power\n return None, None, None, None\n\n# Define the run_simulation function\ndef run_simulation():\n muscle_params = {\n \"onoff\": [input.onset(), input.offset()],\n \"freq\": input.cycle_freq(),\n \"excursion\": input.excursion(),\n \"L0\": input.length_optimal(),\n \"F0\": input.max_isometric_force(),\n \"Vx\": input.max_velocity(),\n \"af\": input.force_velocity_curvature(),\n \"tau_a\": input.activation_time(),\n \"tau_d\": input.deactivation_time(),\n }\n if input.optimize():\n sim_results, _, _, _ = thelen_muscle_opt(\n input.cycle_freq(), input.excursion(), input.length_optimal(),\n input.max_isometric_force(), input.max_velocity(),\n input.force_velocity_curvature(), input.activation_time(),\n input.deactivation_time()\n )\n else:\n sim_results = thelen_muscle(**muscle_params)\n\n return sim_results\n\n# Define the UI layout\nwith ui.sidebar():\n ui.input_slider(\"onset\", \"Onset (% of cycle)\", min=20, max=25, value=22),\n ui.input_slider(\"offset\", \"Offset (% of cycle)\", min=26, max=100, value=66),\n ui.input_slider(\"excursion\", \"Excursion amplitude (mm)\", min=1, max=50, value=20),\n ui.input_slider(\"cycle_freq\", \"Cycle frequency (Hz)\", min=0.5, max=4.5, value=2.0),\n ui.input_numeric(\"length_optimal\", \"Length optimal (m)\", value=0.084),\n ui.input_numeric(\"max_isometric_force\", \"Max isometric force (N)\", value=1871),\n ui.input_numeric(\"max_velocity\", \"Max velocity (fiber lengths/s)\", value=10),\n ui.input_numeric(\"force_velocity_curvature\", \"Force-velocity curvature\", value=0.30),\n ui.input_numeric(\"activation_time\", \"Activation time (ms)\", value=10),\n ui.input_numeric(\"deactivation_time\", \"Deactivation time (ms)\", value=40),\n ui.input_action_button(\"run_sim\", \"Run Simulation\"),\n ui.input_checkbox(\"optimize\", \"Optimize Onset/Offset\", value=False)\n\n\nwith ui.card():\n with ui.navset_bar(title=\"Virtual Muscle Lab\"):\n with ui.nav_panel(title=\"Graphs\"):\n @render.plot\n def combined_graphs():\n sim_results = run_simulation()\n if sim_results is None:\n print(\"Simulation failed: sim_results is None\")\n return\n\n # Create a 2x2 grid of subplots\n fig, axs = plt.subplots(2, 2, figsize=(12, 10)) # 2 rows, 2 columns\n\n # Top-left: Force vs. % of Cycle\n \n force_total = sim_results['sim_data']['force_total']\n cycle_pct = sim_results['sim_data']['cycle_pct']\n axs[0, 0].plot(cycle_pct, force_total)\n axs[0, 0].set_title(\"Force vs. % of Cycle\")\n axs[0, 0].set_xlabel(\"% of Cycle\")\n axs[0, 0].set_ylabel(\"Force (N)\")\n\n # Top-right: Velocity vs. % of Cycle\n velocity = sim_results['sim_data']['velocity']\n axs[0, 1].plot(cycle_pct, velocity, color=\"green\")\n axs[0, 1].set_title(\"Velocity vs. % of Cycle\")\n axs[0, 1].set_xlabel(\"% of Cycle\")\n axs[0, 1].set_ylabel(\"Velocity (m/s)\")\n\n # Bottom-left: Position vs. % of Cycle\n position = sim_results['sim_data']['position']\n axs[1, 0].plot(cycle_pct, position, color=\"orange\")\n axs[1, 0].set_title(\"Position vs. % of Cycle\")\n axs[1, 0].set_xlabel(\"% of Cycle\")\n axs[1, 0].set_ylabel(\"Position (m)\")\n\n # Bottom-right: Power vs. % of Cycle\n power = sim_results['sim_data']['power']\n axs[1, 1].plot(cycle_pct, power, color=\"red\")\n axs[1, 1].set_title(\"Power vs. % of Cycle\")\n axs[1, 1].set_xlabel(\"% of Cycle\")\n axs[1, 1].set_ylabel(\"Power (W)\")\n\n # Adjust layout\n fig.tight_layout()\n return\n \n combined_graphs()\n\n @render.plot\n def work_loop1():\n sim_results = run_simulation()\n if sim_results is None:\n print(\"Simulation failed: sim_results is None\")\n return\n\n fig, ax = plt.subplots()\n # Extract force and position data for the work-loop graph\n force_total = sim_results['sim_data']['force_total']\n position = sim_results['sim_data']['position']\n\n # Plot force vs. position (excursion)\n ax.plot(position, force_total, label=\"Work Loop\")\n\n ax.set_title(\"Work Loop (Force vs. Excursion)\")\n ax.set_xlabel(\"Excursion (m)\") # or \"Position (m)\"\n ax.set_ylabel(\"Force (N)\")\n ax.legend()\n\n return fig\n\n with ui.nav_panel(title=\"Graphs2\"):\n \n# Define Server logic and plotting\n \n @render.plot\n def force_cycle():\n sim_results = run_simulation()\n if sim_results is None:\n print(\"Simulation failed: sim_results is None\")\n return\n fig, ax = plt.subplots()\n sim_results = run_simulation()\n ax.plot(sim_results['sim_data']['cycle_pct'], sim_results['sim_data']['force_total'])\n ax.set_title(\"Force vs. % of Cycle\")\n return fig\n\n\n @render.plot\n def velocity_cycle():\n sim_results = run_simulation()\n if sim_results is None:\n print(\"Simulation failed: sim_results is None\")\n return\n fig, ax = plt.subplots()\n ax.plot(sim_results['sim_data']['cycle_pct'], sim_results['sim_data']['velocity'])\n ax.set_title(\"Velocity vs. % of Cycle\")\n return fig\n\n \n @render.plot\n def position_cycle():\n sim_results = run_simulation()\n if sim_results is None:\n print(\"Simulation failed: sim_results is None\")\n return\n fig, ax = plt.subplots()\n ax.plot(sim_results['sim_data']['cycle_pct'], sim_results['sim_data']['position'])\n ax.set_title(\"Position vs. % of Cycle\")\n return fig\n\n \n @render.plot\n def power_cycle():\n sim_results = run_simulation()\n if sim_results is None:\n print(\"Simulation failed: sim_results is None\")\n return\n fig, ax = plt.subplots()\n ax.plot(sim_results['sim_data']['cycle_pct'], sim_results['sim_data']['power'])\n ax.set_title(\"Power vs. % of Cycle\")\n return fig\n\n @render.plot\n def work_loop():\n sim_results = run_simulation()\n if sim_results is None:\n print(\"Simulation failed: sim_results is None\")\n return\n\n fig, ax = plt.subplots()\n\n # Extract force and position data for the work-loop graph\n force_total = sim_results['sim_data']['force_total']\n position = sim_results['sim_data']['position']\n\n # Plot force vs. position (excursion)\n ax.plot(position, force_total, label=\"Work Loop\")\n\n ax.set_title(\"Work Loop (Force vs. Excursion)\")\n ax.set_xlabel(\"Excursion (m)\") # or \"Position (m)\"\n ax.set_ylabel(\"Force (N)\")\n ax.legend()\n\n return fig\n\n \n @render.table\n def results():\n sim_results = run_simulation()\n if sim_results is None:\n print(\"Simulation failed: sim_results is None\")\n return pd.DataFrame()\n return pd.DataFrame({\n \"Total Work\": [sim_results['work_actual']],\n \"Positive Work\": [sim_results['work_positive']],\n \"Negative Work\": [sim_results['work_negative']],\n \"Power\": [sim_results['power_actual']]\n })\n\n# Create the Shiny app instance\n\n", "type": "text"}]