Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cellpack/autopack/DBRecipeHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ def upload_recipe(self, recipe_meta_data, recipe_data):
recipe_to_save = self.upload_collections(recipe_meta_data, recipe_data)
recipe_to_save["recipe_path"] = self.db.create_path("recipes", recipe_id)
self.upload_data("recipes", recipe_to_save, recipe_id)
return recipe_id

def upload_config(self, config_data, source_path):
"""
Expand All @@ -526,7 +527,7 @@ def upload_config(self, config_data, source_path):
# update the config data with the firebase doc path
config_data["config_path"] = doc_path
self.db.update_doc("configs", id, config_data)
return
return id

def upload_result_metadata(self, file_name, url, job_id=None):
"""
Expand Down
8 changes: 5 additions & 3 deletions cellpack/autopack/upy/simularium/simularium_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1394,21 +1394,23 @@ def post_and_open_file(self, file_name, open_results_in_browser=True):
simulariumHelper.open_in_simularium(url)

@staticmethod
def store_result_file(file_path, storage=None, batch_job_id=None):
def store_result_file(
file_path, storage=None, batch_job_id=None, sub_folder="simularium"
):
if storage == "aws":
handler = DATABASE_IDS.handlers().get(storage)
# if batch_job_id is not None, then we are in a batch job and should use the temp bucket
# TODO: use cellpack-results bucket for batch jobs once we have the correct permissions
if batch_job_id:
initialized_handler = handler(
bucket_name="cellpack-demo",
sub_folder_name="simularium",
sub_folder_name=sub_folder,
region_name="us-west-2",
)
else:
initialized_handler = handler(
bucket_name="cellpack-results",
sub_folder_name="simularium",
sub_folder_name=sub_folder,
region_name="us-west-2",
)
file_name, url = initialized_handler.save_file_and_get_url(file_path)
Expand Down
54 changes: 51 additions & 3 deletions cellpack/bin/upload.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import sys
import fire
import json

from cellpack.autopack.FirebaseHandler import FirebaseHandler
from cellpack.autopack.DBRecipeHandler import DBUploader, DBMaintenance

from cellpack.autopack.upy.simularium.simularium_helper import simulariumHelper
from cellpack.autopack.interface_objects.database_ids import DATABASE_IDS
from cellpack.autopack.loaders.config_loader import ConfigLoader
from cellpack.autopack.loaders.recipe_loader import RecipeLoader
Expand Down Expand Up @@ -32,12 +33,40 @@ def upload(
recipe_path=None,
config_path=None,
db_id=DATABASE_IDS.FIREBASE,
studio: bool = False,
fields: str = None,
name: str = None,
output_file: str = None,
):
"""
Uploads a recipe to the database

:param recipe: string argument
path to local recipe file to upload to firebase
:param config: string argument
path to local config file to upload to firebase
:param db_id: string argument
database ID to use for the upload
:param studio: boolean argument
upload for use in cellPACK studio if True
:param fields: string argument
path to local editable fields file to upload to firebase
:param name: string argument
display name for recipe in studio selection menu
:param output_file: string argument
path to local simularium output file to upload
Comment on lines +54 to +57
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the doc strings are very clear and helpful!


:return: void
"""
if studio and (not name or not recipe_path or not fields):
sys.exit(
"To upload a recipe for cellPACK studio, please provide --name, --recipe_path, and --fields arguments."
)

recipe_id = ""
config_id = ""
result_url = ""
editable_fields_ids = []
if db_id == DATABASE_IDS.FIREBASE:
# fetch the service key json file
db_handler = FirebaseHandler()
Expand All @@ -47,10 +76,29 @@ def upload(
recipe_loader = RecipeLoader(recipe_path)
recipe_full_data = recipe_loader._read(resolve_inheritance=False)
recipe_meta_data = get_recipe_metadata(recipe_loader)
db_handler.upload_recipe(recipe_meta_data, recipe_full_data)
recipe_id = db_handler.upload_recipe(recipe_meta_data, recipe_full_data)
if config_path:
config_data = ConfigLoader(config_path).config
db_handler.upload_config(config_data, config_path)
config_id = db_handler.upload_config(config_data, config_path)
if fields:
editable_fields_data = json.load(open(fields, "r"))
for field in editable_fields_data.get("editable_fields", []):
id, _ = db_handler.upload_data("editable_fields", field)
editable_fields_ids.append(id)
if output_file:
_, result_url = simulariumHelper.store_result_file(
output_file, storage="aws", sub_folder="client"
)
if studio:
recipe_metadata = {
"name": name,
"recipe": recipe_id,
"config": config_id,
"editable_fields": editable_fields_ids,
"result_path": result_url,
}
# Upload the combined recipe metadata to example_packings collection for studio
db_handler.upload_data("example_packings", recipe_metadata)

else:
db_maintainer = DBMaintenance(db_handler)
Expand Down
14 changes: 14 additions & 0 deletions docs/STUDIO_SITE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# cellPACK Studio Site

cellPACK studio allows users to edit example recipes, run packings, and visualize results in the browser.

* Production site: https://cellpack.allencell.org/
* GitHub repository: https://github.com/AllenCell/cellpack-client

### Publishing Recipes to cellPACK Studio
To add new example recipes to the client site, the recipe and its associated metadata must be uploaded to Firebase.

1. Set up access to the staging Firebase account, following [these instructions](https://github.com/mesoscope/cellpack/blob/main/docs/REMOTE_DATABASES.md#firebase-firestore)
2. Determine which recipe fields should be editable in the client, and create a JSON file specifying these editable fields following the schema outlined in [this example](https://github.com/mesoscope/cellpack/blob/0f140859824086d73edab008ff381b5e5717db8b/examples/client-data/example_editable_fields.json)
3. Follow cellPACK installation requirements [in README](https://github.com/mesoscope/cellpack?tab=readme-ov-file#installation)
4. Run the following script to upload necessary files to Firebase: `upload -s -r <path_to_recipe_file> -c <path_to_config_file> -f <path_to_editable_fields_file> -n "Name of Recipe" -o <local_path_to_simularium_result_file>`
70 changes: 70 additions & 0 deletions examples/client-data/example_editable_fields.json
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it! The structure makes much more sense now, just two quick thoughts here:

  • do we want to add step_size to settings at all?
  • for gradient strength, we could wait for the decision on decay_length display

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could definitely add step_size and change the terminology to decay_length! But those changes also need to happen on the cellpack-client site side of things, currently the client wouldn't read either of those two fields, so I would be hesitant to update this example documentation until those changes are actually in effect on the client side.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"editable_fields": [
{
"name": "Display Name",
"description": "Description text",
"path": "path.to.field.in.recipe.json",
"data_type": "integer/float/string",
"input_type": "slider/dropdown/gradient"
},
{
"name": "Endosome Count",
"description": "Number of spheres to be packed",
"path": "composition.membrane.regions.interior.1.count",
"data_type": "integer",
"input_type": "slider",
"min": 0,
"max": 300
},
{
"name": "Endosome Radius",
"description": "Radius of spheres",
"path": "objects.endosome.radius",
"data_type": "float",
"input_type": "slider",
"min": 0,
"max": 10,
"unit": "µm",
"conversion_factor": 0.108
},
{
"name": "Spatial Distribution Rule",
"description": "Choose from one of the listed gradient types",
"path": "objects.endosome.gradient",
"data_type": "gradient",
"input_type": "gradient",
"gradient_options": [
{
"display_name": "Nuclear Bias",
"value": "nucleus_gradient",
"path": "objects.endosome.gradient",
"packing_mode": "gradient",
"packing_mode_path": "objects.endosome.packing_mode",
"strength_path": "gradients.nucleus_gradient.weight_mode_settings.decay_length",
"strength_display_name": "Decay Length",
"strength_description": "Smaller decay length indicates stronger bias",
"strength_min": 0,
"strength_max": 1
},
{
"display_name": "Membrane Bias",
"value": "membrane_gradient",
"path": "objects.endosome.gradient",
"packing_mode": "gradient",
"packing_mode_path": "objects.endosome.packing_mode",
"strength_path": "gradients.membrane_gradient.weight_mode_settings.decay_length",
"strength_display_name": "Decay Length",
"strength_description": "Smaller decay length indicates stronger bias",
"strength_min": 0,
"strength_max": 1
},
{
"display_name": "Unbiased",
"value": "random",
"path": "objects.endosome.packing_mode",
"packing_mode": "random"
}
]
}
]
}
Loading