{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook is an interactive version of the [media cost analysis][liz-paper] by Liz Specht. This is something I put together mostly as an excuse to learn Jupyter widgets, rather than as a public resource. That said, if you find it useful, great!\n", "\n", "Liz's analysis explores how the cost of Essential 8 media would change under various scenarios in which the costs and/or concentrations of individual components are reduced. It does not look at alternative media formulations using e.g. plant hydrolysates, which could further bring down the cost of culture media.\n", "\n", "In this notebook, I built sliders just for the costs of individual components. Concentrations could have sliders too, but I didn't get around to putting these in.\n", "\n", "[liz-paper]: https://www.gfi.org/files/sci-tech/clean-meat-production-volume-and-medium-cost.pdf" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "import ipywidgets as widgets\n", "from ipywidgets import interact\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "# Costs expressed as $ per gram, except DMEM/F12 which is per 50L (see table 1 of Liz's cost analysis)\n", "# Concentrations are mg/L, except for DMEM/F12 which is 1x\n", "\n", "cost_bm = 156\n", "cost_aa2p = 7.84\n", "cost_nahco3 = 0.01\n", "cost_selenite = 0.1\n", "cost_insulin = 340\n", "cost_transferrin = 400\n", "cost_fgf = 2005000\n", "cost_tgf = 80900000\n", "\n", "conc_bm = 1\n", "conc_aa2p = 64\n", "conc_nahco3 = 543\n", "conc_selenite = 0.014\n", "conc_insulin = 19.4\n", "conc_transferrin = 10.7\n", "conc_fgf = 0.1\n", "conc_tgf = 0.002\n", "\n", "costs = [cost_aa2p, cost_nahco3, cost_selenite, cost_insulin, cost_transferrin, cost_fgf, cost_tgf]\n", "concs = [conc_aa2p, conc_nahco3, conc_selenite, conc_insulin, conc_transferrin, conc_fgf, conc_tgf]\n", "labels = ['AA2P', 'NaHCO3', 'Na Selenite', 'Insulin', 'Transferrin', 'FGF', 'TGFbeta']\n", "\n", "def get_cost(costs, concs, cost_bm = 156, conc_bm = 1, return_breakdown = False):\n", " breakdown = [(cost_bm * conc_bm) / 50]\n", " for cost, conc in zip (costs, concs):\n", " breakdown.append(cost * conc / 1000)\n", " cost_L = sum(breakdown)\n", " if return_breakdown:\n", " return cost_L, breakdown\n", " else:\n", " return cost_L\n", " \n", "def show_outputs(costs, new_costs, output):\n", " output.clear_output()\n", " \n", " with output: \n", " cost, breakdown = get_cost(costs, concs, return_breakdown = True)\n", " pie1 = plt.pie(breakdown, labels = ['Basal media'] + labels, wedgeprops=dict(width=0.5))\n", " plt.gca().set_title('Original cost: ' + str(round(cost, 2)) + ' (USD)')\n", " plt.show()\n", "\n", " new_cost, new_breakdown = get_cost(new_costs, concs, return_breakdown = True)\n", " pie2 = plt.pie(new_breakdown, labels = ['Basal media'] + labels, wedgeprops=dict(width=0.5))\n", " plt.gca().set_title('New cost: ' + str(round(new_cost, 2)) + ' (USD)')\n", " plt.show()\n", " \n", "def make_plot(cost_dict, to_plot, cost_range, plot_output):\n", " plot_output.clear_output()\n", " with plot_output:\n", " y = []\n", " for component_cost in cost_range:\n", " cost_dict[dropdown.value] = component_cost\n", " y.append(get_cost(cost_dict.values(), concs))\n", " \n", " plt.plot(cost_range, y)\n", " plt.xlabel(dropdown.value + ' cost per gram')\n", " plt.ylabel('Media cost per liter')\n", " plt.show()\n", " \n" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "output = widgets.Output()\n", "plot_output = widgets.Output()\n", "\n", "# Make text box widgets\n", "\n", "t_aa2p = widgets.FloatText(value = cost_aa2p, description = 'AA2P')\n", "t_nahco3 = widgets.FloatText(value = cost_nahco3, description = 'NaHCO3')\n", "t_selenite = widgets.FloatText(value = cost_selenite, description = 'Na Selenite')\n", "t_insulin = widgets.IntText(value = cost_insulin, description = 'Insulin')\n", "t_transferrin = widgets.IntText(value = cost_transferrin, description = 'Transferrin')\n", "t_fgf = widgets.IntText(value = cost_fgf, description = 'FGF')\n", "t_tgf = widgets.IntText(value = cost_tgf, description = 'TGFbeta')\n", "\n", "t_widgets = [t_aa2p, t_nahco3, t_selenite, t_insulin, t_transferrin, t_fgf, t_tgf]\n", "widget_dict = {label: widget for label, widget in zip(labels, t_widgets)}\n", "\n", "# Could easily add a second column to represent concentrations\n", "\n", "dropdown = widgets.Dropdown(options = labels, description = 'Plot')\n", "lower_bound_widget = widgets.FloatText(value = 0, description = 'Lower bound')\n", "upper_bound_widget = widgets.FloatText(value = widget_dict[dropdown.value].value, description = 'Upper bound')\n", "\n", "plot_widgets = [dropdown, lower_bound_widget, upper_bound_widget]\n", "\n", "def handler(change):\n", " new_costs = [t.value for t in t_widgets]\n", " show_outputs(costs, new_costs, output)\n", " \n", "def plot_handler(change):\n", " new_costs = [t.value for t in t_widgets]\n", " cost_dict = {label: cost for label, cost in zip(labels, new_costs)}\n", " to_plot = dropdown.value\n", " cost_range = [lower_bound_widget.value, upper_bound_widget.value]\n", " make_plot(cost_dict, to_plot, cost_range, plot_output)\n", " \n", "def widget_handler(change):\n", " lower_bound_widget.value = 0\n", " upper_bound_widget.value = widget_dict[dropdown.value].value\n", "\n", "for t_widget in t_widgets:\n", " t_widget.observe(handler, names = 'value')\n", " t_widget.observe(plot_handler, names = 'value')\n", "for plot_widget in plot_widgets:\n", " plot_widget.observe(plot_handler, names = 'value')\n", "dropdown.observe(widget_handler, names = 'value')\n", "\n", "static_title = widgets.HTML('Calculate a single scenario')\n", "range_title = widgets.HTML('Calculate costs over a range (will use costs from the single scenario except for the selected component)')\n", "\n", "input_widgets = widgets.HBox([widgets.VBox([static_title] + t_widgets), widgets.VBox([range_title] + plot_widgets)])\n", "tab = widgets.GridBox([output, plot_output], layout=widgets.Layout(grid_template_columns=\"repeat(2, 400px)\"))\n", "dashboard = widgets.VBox([input_widgets, tab])\n", "\n", "handler(None)\n", "plot_handler(None)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ecff957607c34e15a63a532775d87e68", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(VBox(children=(HTML(value='Calculate a single scenario'), FloatText(value…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(dashboard)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }