Skip to content

Commit

Permalink
Merge pull request #28 from biosimulations/show-saved-plots
Browse files Browse the repository at this point in the history
show saved plots from simulators in notebook
  • Loading branch information
jcschaff authored Feb 10, 2025
2 parents 04824e9 + b392395 commit c850520
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 76 deletions.
Empty file.
82 changes: 82 additions & 0 deletions biosim_client/verify/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
from io import BytesIO
from typing import TypeAlias
from zipfile import ZIP_DEFLATED, ZipFile

import fitz # type: ignore
import matplotlib.pyplot as plt
import numpy as np
import PIL
import urllib3
from IPython.display import Markdown, display
from PIL.Image import Image
from PIL.PngImagePlugin import PngImageFile

from biosim_client.api.biosim.models.biosim_simulation_run import BiosimSimulationRun
from biosim_client.api.biosim.models.biosimulator_version import BiosimulatorVersion
Expand Down Expand Up @@ -229,6 +236,81 @@ def _create_markdown_report(self) -> str:
simulator_markdown += f"- no match for {run_link_map[run_group[0].id]} (closest score {min_score})\n"
return simulator_markdown

def show_saved_plots(self, max_columns: int = 3, width_in: float = 10) -> None:
images: list[Image] = []
image_run_ids = []
image_not_found_run_ids = []
sim_version_names = self.simulator_version_names
http = urllib3.PoolManager()
for run_id in self.run_ids:
pdf_images: list[PngImageFile] = self._retrieve_pdf_as_image(run_id=run_id, http=http)
if len(pdf_images) == 0:
image_not_found_run_ids.append(run_id)
elif len(pdf_images) == 1:
images.append(pdf_images[0])
image_run_ids.append(run_id)
else:
# concatenate all images in pdf_images into a single image
width = max([image.width for image in pdf_images])
height = sum([image.height for image in pdf_images])
new_image = PIL.Image.new("RGB", (width, height))
y_offset = 0
for image in pdf_images:
new_image.paste(image, (0, y_offset))
y_offset += image.height
images.append(new_image)
# images.append(ImageFile(new_image.tobytes("png")))
image_run_ids.append(run_id)

if len(images) == 0:
display(f"no saved plots for runs {image_not_found_run_ids}") # type: ignore
return

# determine number of columns and rows, start with max_columns and reduce to two columns
# until the number of images is divisible (or almost divisible) by number of columns
ncols = min(len(images), max_columns)
while len(images) % ncols != 0 and len(images) % ncols != (ncols - 1) and ncols > 2:
ncols -= 1
nrows = len(images) // ncols + 1

width_pixels = max([image.width for image in images]) * ncols
height_pixels = max([image.height for image in images]) * nrows
height_in = width_in * height_pixels / width_pixels
figsize = (width_in, height_in)
fig, ax = plt.subplots(ncols=ncols, nrows=nrows, figsize=figsize)
ax = ax.flatten()
for i in range(nrows * ncols):
if i >= len(images):
ax[i].axis("off")
ax[i].set_title("")
ax[i].set_visible(False)
else:
ax[i].axis("off")
ax[i].set_title(f"{sim_version_names[i]}")
ax[i].imshow(images[i])

plt.tight_layout()
plt.show()

def _retrieve_pdf_as_image(self, run_id: str, http: urllib3.PoolManager) -> list[PngImageFile]:
pdf_url = f"https://api.biosimulations.org/results/{run_id}/download"
images: list[PngImageFile] = []
head_response = http.request("HEAD", pdf_url)
if head_response.status == 200:
response = http.request("GET", pdf_url)
with BytesIO(response.data) as zip_buffer, ZipFile(zip_buffer, "a", ZIP_DEFLATED, False) as zip_file:
file_names = zip_file.namelist()
for file_name in file_names:
if file_name.endswith(".pdf") and file_name.lower().index("plot") != -1:
with zip_file.open(file_name) as pdf_file:
content = pdf_file.read()
with fitz.open(stream=content, filetype="pdf") as doc:
for page in doc:
pix: fitz.Pixmap = page.get_pixmap()
png_content = pix.tobytes("png")
images.append(PIL.Image.open(BytesIO(png_content))) # type: ignore
return images


def _extract_dataset_attr(
dataset_name: str, attr_key: str, hdf5_file: BiosimHDF5File | SimDataHDF5File
Expand Down
13 changes: 12 additions & 1 deletion notebooks/verify-demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,17 @@
{
"cell_type": "code",
"execution_count": null,
"id": "75fa30ae7e01483c",
"id": "1cec8049-5ca4-4b45-b68c-773cc7fc8a11",
"metadata": {},
"outputs": [],
"source": [
"run.show_saved_plots(max_columns=4, width_in=10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "82c8576f-030b-4e31-ba95-7f93cb4a5637",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -45,6 +55,7 @@
"omex_file = \"/Users/jimschaff/Documents/workspace/biosim-client/tests/fixtures/data/BIOMD0000000010_tellurium_Negative_feedback_and_ultrasen.omex\"\n",
"run_2: VerifyResults = BiosimClient().compare_omex(omex_path=omex_file, simulators=simulators)\n",
"run_2.show_report()\n",
"run_2.show_saved_plots()\n",
"run_2.show_dataset_heatmaps()"
]
},
Expand Down
Loading

0 comments on commit c850520

Please sign in to comment.