Skip to content
Snippets Groups Projects

Data explorer

1 file
+ 144
163
Compare changes
  • Side-by-side
  • Inline
+ 144
163
@@ -21,13 +21,14 @@ class Interface:
self.height = 1024
self.width = 900
self.operations = [
"Data summary",
"Z Slicer",
"Y Slicer",
"X Slicer",
"Z max projection",
"Z min projection",
"Intensity histogram",
"Data summary",
]
# CSS path
current_dir = os.path.dirname(os.path.abspath(__file__))
@@ -55,10 +56,10 @@ class Interface:
def set_visible(self):
return gr.update(visible=True)
def set_spinner(self):
def set_spinner(self, message):
return gr.update(
elem_classes="btn btn-spinner",
value=f"Processing...",
value=f"{message}",
interactive=False,
)
@@ -128,7 +129,7 @@ class Interface:
gr.Markdown("### Operations")
operations = gr.CheckboxGroup(
choices=self.operations,
value=[self.operations[0], self.operations[1]],
value=[self.operations[0], self.operations[-1]],
label=None,
container=False,
interactive=True,
@@ -140,15 +141,6 @@ class Interface:
# Visualization and results
with gr.Row(elem_classes="mt-64"):
# Text box with data summary
with gr.Column(visible=False) as result_data_summary:
data_summary = gr.Text(
lines=24,
label=None,
show_label=False,
elem_classes="monospace-box",
value="Data summary",
)
# Z Slicer
with gr.Column(visible=False) as result_z_slicer:
@@ -187,7 +179,16 @@ class Interface:
# Intensity histogram
with gr.Column(visible=False) as result_intensity_histogram:
hist_plot = gr.Plot(label="Volume intensity histogram")
# Text box with data summary
with gr.Column(visible=False) as result_data_summary:
data_summary = gr.Text(
lines=24,
label=None,
show_label=False,
elem_classes="monospace-box",
value="Data summary",
)
### Gradio objects lists
session = gr.State([])
@@ -195,13 +196,13 @@ class Interface:
# Results
results = [
result_data_summary,
result_z_slicer,
result_y_slicer,
result_x_slicer,
result_z_max_projection,
result_z_min_projection,
result_intensity_histogram,
result_data_summary,
]
# Inputs
inputs = [
@@ -217,47 +218,45 @@ class Interface:
]
# Outputs
outputs = [
data_summary,
zslice_plot,
yslice_plot,
xslice_plot,
max_projection_plot,
min_projection_plot,
hist_plot,
data_summary,
]
projection_outputs = [session, max_projection_plot, min_projection_plot]
### Listeners
spinner_session = gr.Text("Starting session...", visible=False)
spinner_loading = gr.Text("Loading data...", visible=False)
spinner_operations = gr.Text("Running pipeline...", visible=False)
# fmt: off
reload_base_path.click(fn=self.update_explorer,inputs=base_path, outputs=explorer)
btn_run.click(
fn=self.set_spinner, inputs=[], outputs=btn_run).success(
fn=self.start_session, inputs=inputs, outputs=session).success(
fn=pipeline.run_pipeline, inputs=session, outputs=outputs).success(
# fn=pipeline.process_input, inputs=session, outputs=session).success(
# fn=pipeline.show_summary_str, inputs=session, outputs=data_summary).success(
# fn=pipeline.create_zslice_fig, inputs=session, outputs=zslice_plot).success(
# fn=pipeline.create_yslice_fig, inputs=session, outputs=yslice_plot).success(
# fn=pipeline.create_xslice_fig, inputs=session, outputs=xslice_plot).success(
# fn=pipeline.create_projections_figs, inputs=session, outputs=projection_outputs).success(
# fn=pipeline.show_summary_str, inputs=session, outputs=data_summary).success(
# fn=pipeline.plot_vol_histogram, inputs=session, outputs=hist_plot).success(
fn=self.show_results, inputs=operations, outputs=results).success(
fn=self.set_spinner, inputs=spinner_session, outputs=btn_run).then(
fn=self.start_session, inputs=inputs, outputs=session).then(
fn=self.set_spinner, inputs=spinner_loading, outputs=btn_run).then(
fn=pipeline.load_data, inputs=session, outputs=session).then(
fn=self.set_spinner, inputs=spinner_operations, outputs=btn_run).then(
fn=pipeline.run_pipeline, inputs=session, outputs=outputs).then(
fn=self.show_results, inputs=operations, outputs=results).then(
fn=self.set_relaunch_button, inputs=[], outputs=btn_run)
zpos.release(
fn=self.update_zpos, inputs=[session, zpos], outputs=[session, zslice_plot]).success(
fn=pipeline.create_zslice_fig, inputs=session, outputs=zslice_plot,show_progress=False)
fn=pipeline.create_zslice_fig, inputs=[], outputs=zslice_plot,show_progress="hidden")
ypos.release(
fn=self.update_ypos, inputs=[session, ypos], outputs=[session, yslice_plot]).success(
fn=pipeline.create_yslice_fig, inputs=session, outputs=yslice_plot,show_progress=False)
fn=pipeline.create_yslice_fig, inputs=[], outputs=yslice_plot,show_progress="hidden")
xpos.release(
fn=self.update_xpos, inputs=[session, xpos], outputs=[session, xslice_plot]).success(
fn=pipeline.create_xslice_fig, inputs=session, outputs=xslice_plot,show_progress=False)
fn=pipeline.create_xslice_fig, inputs=[], outputs=xslice_plot,show_progress="hidden")
# fmt: on
@@ -266,8 +265,6 @@ class Interface:
def start_session(self, *args):
# Starts a new session dictionary
session = Session()
session.root_path = os.path.expanduser("~")
session.interface = "gradio"
session.all_operations = Interface().operations
session.operations = args[0]
session.base_path = args[1]
@@ -331,9 +328,7 @@ class Interface:
class Session:
def __init__(self):
self.root_path = os.path.expanduser("~")
self.virtual_stack = False
self.interface = None
self.file_path = None
self.vol = None
self.zpos = 0.5
@@ -343,7 +338,9 @@ class Session:
self.dataset_name = None
self.error_message = None
self.file_path = None
self.max_projection = None
self.min_projection = None
self.projections_calculated = False
# Volume info
self.zsize = None
self.ysize = None
@@ -362,55 +359,6 @@ class Session:
# Histogram
self.nbins = 32
def get_data_info(self):
# Open file
try:
vol = load(
self.file_path,
virtual_stack=self.virtual_stack,
dataset_name=self.dataset_name,
)
except Exception as error_message:
self.error_message = error_message
return
first_slice = vol[0]
# Get info
self.zsize = len(vol)
self.ysize, self.xsize = first_slice.shape
self.data_type = str(first_slice.dtype)
self.last_modified = datetime.datetime.fromtimestamp(
os.path.getmtime(self.file_path)
).strftime("%Y-%m-%d %H:%M")
self.file_size = os.path.getsize(self.file_path)
def create_summary_dict(self):
# Create dictionary
if self.error_message:
self.summary_dict = {"error_mesage": self.error_message}
else:
self.summary_dict = {
"Last modified": self.last_modified,
"File size": internal_tools.sizeof(self.file_size),
"Z-size": str(self.zsize),
"Y-size": str(self.ysize),
"X-size": str(self.xsize),
"Data type": self.data_type,
"Min value": self.min_value,
"Mean value": self.mean_intensity,
"Max value": self.max_value,
}
def summary_str(self):
if "error_mesage" in self.summary_dict:
error_box = ouf.boxtitle("ERROR", return_str=True)
return f"{error_box}\n{self.summary_dict['error_mesage']}"
else:
display_dict = {k: v for k, v in self.summary_dict.items() if v is not None}
return ouf.showdict(display_dict, return_str=True, title="Data summary")
def zslice_from_zpos(self):
self.zslice = int(self.zpos * (self.zsize - 1))
@@ -434,100 +382,123 @@ class Pipeline:
self.verbose = False
self.session = None
def load_data(self, session):
try:
session.vol = load(
session.file_path,
virtual_stack=session.virtual_stack,
dataset_name=session.dataset_name,
)
except Exception as error_message:
raise ValueError(
f"Failed to load the image: {error_message}"
) from error_message
session = self.get_data_info(session)
return session
def get_data_info(self, session):
first_slice = session.vol[0]
# Get info
session.zsize = len(session.vol)
session.ysize, session.xsize = first_slice.shape
session.data_type = str(first_slice.dtype)
session.last_modified = datetime.datetime.fromtimestamp(
os.path.getmtime(session.file_path)
).strftime("%Y-%m-%d %H:%M")
session.file_size = os.path.getsize(session.file_path)
return session
def run_pipeline(self, session):
self.session = session
outputs = []
print(session.all_operations)
log.info(session.all_operations)
for operation in session.all_operations:
if operation in session.operations:
outputs.append(self.run_operation(operation))
else:
print(f"Skipping {operation}")
log.info(f"Skipping {operation}")
outputs.append(None)
return outputs
def run_operation(self, operation):
print(f"Running {operation}")
log.info(f"Running {operation}")
if operation == "Data summary":
return "Hello from Pipeline!"
return self.show_data_summary()
elif operation == "Z Slicer":
return None
if operation == "Z Slicer":
return self.create_zslice_fig()
elif operation == "Y Slicer":
return None
if operation == "Y Slicer":
return self.create_yslice_fig()
elif operation == "X Slicer":
return None
if operation == "X Slicer":
return self.create_xslice_fig()
elif operation == "Z max projection":
return None
if operation == "Z max projection":
return self.create_projections_figs()[0]
elif operation == "Z min projection":
return None
if operation == "Z min projection":
return self.create_projections_figs()[1]
elif operation == "Intensity histogram":
return None
if operation == "Intensity histogram":
return self.plot_vol_histogram()
else:
raise ValueError("Unknown operation")
# In case nothing was triggered, raise error
raise ValueError("Unknown operation")
def process_input(self):
def show_data_summary(self):
# Get info from Tiff file
self.session.get_data_info()
self.session.create_summary_dict()
# Memory map data as a virtual stack
try:
self.session.vol = load(
self.session.file_path,
virtual_stack=self.session.virtual_stack,
dataset_name=self.session.dataset_name,
)
except:
return session
if self.verbose:
log.info(ouf.br(3, return_str=True) + session.summary_str())
return session
summary_dict = {
"Last modified": self.session.last_modified,
"File size": internal_tools.sizeof(self.session.file_size),
"Z-size": str(self.session.zsize),
"Y-size": str(self.session.ysize),
"X-size": str(self.session.xsize),
"Data type": self.session.data_type,
"Min value": self.session.min_value,
"Mean value": self.session.mean_intensity,
"Max value": self.session.max_value,
}
def show_summary_str(self, session):
session.create_summary_dict()
return session.summary_str()
display_dict = {k: v for k, v in summary_dict.items() if v is not None}
return ouf.showdict(display_dict, return_str=True, title="Data summary")
def create_zslice_fig(self, session):
slice_fig = self.create_slice_fig("z", session)
def create_zslice_fig(self):
slice_fig = self.create_slice_fig("z")
return slice_fig
def create_yslice_fig(self, session):
slice_fig = self.create_slice_fig("y", session)
def create_yslice_fig(self):
slice_fig = self.create_slice_fig("y")
return slice_fig
def create_xslice_fig(self, session):
slice_fig = self.create_slice_fig("x", session)
def create_xslice_fig(self):
slice_fig = self.create_slice_fig("x")
return slice_fig
def create_slice_fig(self, axis, session):
def create_slice_fig(self, axis):
plt.close()
vol = session.vol
plt.set_cmap(session.cmap)
vol = self.session.vol
plt.set_cmap(self.session.cmap)
zslice = session.zslice_from_zpos()
yslice = session.yslice_from_ypos()
xslice = session.xslice_from_xpos()
zslice = self.session.zslice_from_zpos()
yslice = self.session.yslice_from_ypos()
xslice = self.session.xslice_from_xpos()
# Check if we something to use as vmin and vmax
if session.min_percentile and session.max_percentile:
vmin = session.min_percentile
vmax = session.max_percentile
if self.session.min_percentile and self.session.max_percentile:
vmin = self.session.min_percentile
vmax = self.session.max_percentile
else:
vmin = None
vmax = None
@@ -567,55 +538,65 @@ class Pipeline:
return fig
def create_projections_figs(self, session):
vol = session.vol
def create_projections_figs(self):
vol = self.session.vol
# Run projections
max_projection, min_projection = self.get_projections(vol, session)
if not self.session.projections_calculated:
projections = self.get_projections(vol)
self.session.max_projection = projections[0]
self.session.min_projection = projections[1]
# Generate figures
max_projection_fig = self.create_img_fig(
max_projection,
vmin=session.min_percentile,
vmax=session.max_percentile,
self.session.max_projection,
vmin=self.session.min_percentile,
vmax=self.session.max_percentile,
)
min_projection_fig = self.create_img_fig(
min_projection,
vmin=session.min_percentile,
vmax=session.max_percentile,
self.session.min_projection,
vmin=self.session.min_percentile,
vmax=self.session.max_percentile,
)
return session, max_projection_fig, min_projection_fig
def get_projections(self, vol, session):
self.session.projections_calculated = True
return max_projection_fig, min_projection_fig
def get_projections(self, vol):
# Create arrays for iteration
max_projection = np.zeros(np.shape(vol[0]))
min_projection = np.ones(np.shape(vol[0])) * float("inf")
intensity_sum = 0
# Iterate over slices
# Iterate over slices. This is needed in case of virtual stacks.
for zslice in vol:
max_projection = np.maximum(max_projection, zslice)
min_projection = np.minimum(min_projection, zslice)
intensity_sum += np.sum(zslice)
session.min_value = np.min(min_projection)
session.min_percentile = np.percentile(
self.session.min_value = np.min(min_projection)
self.session.min_percentile = np.percentile(
min_projection, 100 - self.display_saturation_percentile
)
session.max_value = np.max(max_projection)
session.max_percentile = np.percentile(
self.session.max_value = np.max(max_projection)
self.session.max_percentile = np.percentile(
max_projection, self.display_saturation_percentile
)
session.intensity_sum = intensity_sum
self.session.intensity_sum = intensity_sum
nvoxels = self.session.zsize * self.session.ysize * self.session.xsize
self.session.mean_intensity = intensity_sum / nvoxels
nvoxels = session.zsize * session.ysize * session.xsize
session.mean_intensity = intensity_sum / nvoxels
return max_projection, min_projection
def plot_vol_histogram(self, session):
def plot_vol_histogram(self):
# The Histogram needs results from the projections
if not self.session.projections_calculated:
_ = self.get_projections(self.session.vol)
vol_hist, bin_edges = self.vol_histogram(
session.vol, session.nbins, session.min_value, session.max_value
self.session.vol, self.session.nbins, self.session.min_value, self.session.max_value
)
fig, ax = plt.subplots(figsize=(6, 4))
Loading