Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init commit of MarkdownWriter class #163

Closed
wants to merge 12 commits into from
186 changes: 82 additions & 104 deletions cellpack/autopack/Analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from cellpack.autopack.upy import colors as col
from cellpack.autopack.upy.colors import map_colors
from cellpack.autopack.utils import check_paired_key, get_paired_key
from cellpack.autopack.writers import MarkdownWriter


class Analysis:
Expand Down Expand Up @@ -969,7 +970,7 @@ def get_dict_from_glob(

def run_distance_analysis(
self,
report_md,
md_object:MarkdownWriter,
recipe_data,
pairwise_distance_dict,
figure_path,
Expand All @@ -991,51 +992,46 @@ def run_distance_analysis(
pairwise_distance_dict
)

report_md.new_header(level=1, title="Distance analysis")
report_md.new_line(
md_object.add_header(level=1, header="Distance analysis")
md_object.report_md.new_line(
f"Expected minimum distance: {expected_minimum_distance:.2f}"
)
report_md.new_line(
md_object.report_md.new_line(
f"Actual minimum distance: {packed_minimum_distance:.2f}\n"
)

if expected_minimum_distance > packed_minimum_distance:
report_md.new_header(
level=2, title="Possible errors", add_table_of_contents="n"
)
report_md.new_list(
md_object.add_header(header="Possible errors")
md_object.report_md.new_list(
[
f"Packed minimum distance {packed_minimum_distance:.2f}"
" is less than the "
f"expected minimum distance {expected_minimum_distance:.2f}\n"
]
)

num_keys = len(all_pairwise_distances.keys())
df = pd.DataFrame()
df['Ingredient key'] = []
df['Pairwise distance distribution'] = []

img_list = []
for ingr_key in all_pairwise_distances:
ingr_distance_histo_path = figure_path.glob(
f"{ingr_key}_pairwise_distances_*.png"
)
ingr_distance_histo_path = figure_path.glob(f"{ingr_key}_pairwise_distances_*.png")
for img_path in ingr_distance_histo_path:
img_list.append(
report_md.new_inline_image(
text=f"Distance distribution {ingr_key}",
path=f"{output_image_location}/{img_path.name}",
md_object.report_md.new_inline_image(
text=f"Distance distribution {ingr_key}",
path= f"{self.output_path}/{img_path.name}"
)
)
text_list = [
"Ingredient key",
"Pairwise distance distribution",
*[
val
for pair in zip(all_pairwise_distances.keys(), img_list)
for val in pair
],
]
)

report_md.new_table(
columns=2, rows=(num_keys + 1), text=text_list, text_align="center"
df = pd.DataFrame()
df['Ingredient key'] = all_pairwise_distances.keys()
df['Pairwise distance distribution'] = img_list

md_object.add_table(
header="",
table=df
)

def get_ingredient_key_from_object_or_comp_name(
Expand Down Expand Up @@ -1096,7 +1092,7 @@ def get_partner_pair_dict(

def run_partner_analysis(
self,
report_md,
md_object:MarkdownWriter,
recipe_data,
combined_pairwise_distance_dict,
ingredient_radii,
Expand All @@ -1112,9 +1108,14 @@ def run_partner_analysis(
avg_num_packed,
)
if len(partner_pair_dict):
report_md.new_header(level=1, title="Partner Analysis")
md_object.add_header(
header="Partner Analysis"
)

val_list = []
paired_keys = []
touching_radii = []
binding_probabilities = []
close_fractions = []
for paired_key, partner_values in partner_pair_dict.items():
pairwise_distances = numpy.array(
combined_pairwise_distance_dict[paired_key]
Expand All @@ -1124,27 +1125,20 @@ def run_partner_analysis(
numpy.count_nonzero(pairwise_distances < padded_radius)
/ partner_values["num_packed"]
)
val_list.extend(
[
paired_key,
partner_values["touching_radius"],
partner_values["binding_probability"],
close_fraction,
]
)

text_list = [
"Partner pair",
"Touching radius",
"Binding probability",
"Close packed fraction",
*val_list,
]
report_md.new_table(
columns=4,
rows=(len(partner_pair_dict) + 1),
text=text_list,
text_align="center",
paired_keys.append(paired_key)
touching_radii.append(partner_values["touching_radius"])
binding_probabilities.append(partner_values["binding_probability"])
close_fractions.append(close_fraction)

df = pd.DataFrame()
df["Partner pair"] = paired_keys
df["Touching radius"] = touching_radii
df["Binding Probability"] = binding_probabilities
df["Close packing fraction"] = close_fractions

md_object.add_table(
header="",
table=df,
)

def create_report(
Expand Down Expand Up @@ -1172,56 +1166,41 @@ def create_report(
run_*_analysis: bool
whether to run specific analysis
"""
if report_output_path is None:
report_output_path = self.output_path
report_output_path = Path(report_output_path)

report_md = MdUtils(
file_name=f"{report_output_path}/analysis_report",
title="Packing analysis report",
)
report_md.new_header(
level=2,
title=f"Analysis for packing results located at {self.packing_results_path}",
add_table_of_contents="n",
)

if not hasattr(self, "ingredient_key_dict"):
self.ingredient_key_dict = self.get_dict_from_glob("ingredient_keys_*")

self.ingredient_key_dict = self.get_dict_from_glob("ingredient_keys_*")
if ingredient_keys is None:
ingredient_keys = list(self.ingredient_key_dict.keys())

avg_num_packed = self.get_number_of_ingredients_packed(
ingredient_keys=ingredient_keys
)
ingredient_radii = self.get_ingredient_radii(recipe_data=recipe_data)

if not hasattr(self, "pairwise_distance_dict"):
self.pairwise_distance_dict = self.get_dict_from_glob(
"pairwise_distances_*.json"
pairwise_distance_dict = self.get_dict_from_glob("pairwise_distances_*.json")
combined_pairwise_distance_dict = self.combine_results_from_seeds(
pairwise_distance_dict
)
if not hasattr(self, "pairwise_distance_dict"):
self.pairwise_distance_dict = self.get_dict_from_glob(
"pairwise_distances_*.json"
)

combined_pairwise_distance_dict = self.combine_results_from_seeds(
self.pairwise_distance_dict
df = pd.DataFrame()
df['Ingredient name'] = list(ingredient_keys)
df["Encapsulating radius"] = list(ingredient_radii.values())
df["Average number packed"] = list(avg_num_packed.values())

# path to save report and other outputs
if output_image_location is None:
output_image_location = self.output_path

md_object = MarkdownWriter(
title="Packing analysis report",
output_path=self.output_path,
output_image_location=output_image_location,
report_name="analysis_report"
)

val_list = []
for key, radius, num_packed in zip(
ingredient_keys, ingredient_radii.values(), avg_num_packed.values()
):
val_list.extend([key, radius, num_packed])
text_list = [
"Ingredient name",
"Encapsulating radius",
"Average number packed",
*val_list,
]
report_md.new_table(
columns=3,
rows=(len(ingredient_keys) + 1),
text=text_list,
text_align="center",
md_object.add_header(
header=f"Analysis for packing results located at {self.packing_results_path}"
)

# path to save report and other outputs
Expand All @@ -1232,21 +1211,17 @@ def create_report(
packing_results_path = self.packing_results_path
figure_path = packing_results_path / "figures"

report_md.new_header(level=1, title="Packing image")
glob_to_packing_image = figure_path.glob("packing_image_*.png")
for img_path in glob_to_packing_image:
report_md.new_line(
report_md.new_inline_image(
text="Packing image",
path=f"{output_image_location}/{img_path.name}",
)
)
report_md.new_line("")
md_object.add_images(
header="Packing image",
image_text=["Packing image"],
filepaths=list(figure_path.glob("packing_image_*.png"))
)


if run_distance_analysis:
# TODO: take packing distance dict as direct input for live mode
self.run_distance_analysis(
report_md,
md_object,
recipe_data,
self.pairwise_distance_dict,
figure_path,
Expand All @@ -1255,14 +1230,14 @@ def create_report(

if run_partner_analysis:
self.run_partner_analysis(
report_md,
md_object,
recipe_data,
combined_pairwise_distance_dict,
ingredient_radii,
avg_num_packed,
)

report_md.create_md_file()
md_object.write_file()

def run_analysis_workflow(
self,
Expand Down Expand Up @@ -1925,7 +1900,10 @@ def add_ingredient_positions_to_plot(
)
# plot the sphere
if ingr.use_rbsphere:
(ext_recipe, pts,) = ingr.getInterpolatedSphere(
(
ext_recipe,
pts,
) = ingr.getInterpolatedSphere(
seed_ingredient_positions[-i - 1],
seed_ingredient_positions[-i],
)
Expand Down
33 changes: 29 additions & 4 deletions cellpack/autopack/FirebaseHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,32 @@ def upload_doc(self, collection, data):
return self.db.collection(collection).add(data)

@staticmethod
def is_firebase_obj(obj):
return isinstance(
obj, (firestore.DocumentReference, firestore.DocumentSnapshot)
)
def create_path(collection, doc_id):
return f"firebase:{collection}/{doc_id}"

# `doc` is a DocumentSnapshot object
# `doc_ref` is a DocumentReference object to perform operations on the doc
def get_doc_by_id(self, collection, id):
doc_ref = self.db.collection(collection).document(id)
doc = doc_ref.get()
if doc.exists:
return doc.to_dict(), doc_ref
else:
return None, None

@staticmethod
def get_collection_id_from_path(path):
# path example = firebase:composition/uid_1
components = path.split(":")[1].split("/")
collection = components[0]
id = components[1]
return collection, id

@staticmethod
def update_reference_on_doc(doc_ref, index, new_item_ref):
doc_ref.update({index: new_item_ref})

@staticmethod
def update_elements_in_array(doc_ref, index, new_item_ref, remove_item):
doc_ref.update({index: firestore.ArrayRemove([remove_item])})
doc_ref.update({index: firestore.ArrayUnion([new_item_ref])})
Loading