Skip to content
Snippets Groups Projects
Commit e8ecc95c authored by Felipe Delestro Matos's avatar Felipe Delestro Matos
Browse files

basic repo organization

parent 88d703e9
No related branches found
No related tags found
No related merge requests found
# Compiled Python files
*.pyc
*.pyo
__pycache__/
# Distribution directories
dist/
build/
*.egg-info/
# Development and editor files
.vscode/
.idea/
*.swp
*.swo
*.pyc
*~
\ No newline at end of file
import gradio as gr
import numpy as np
import os
from ..tools import internal_tools
import tifffile
import outputformat as ouf
import datetime
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
class AppInterface:
def __init__(self):
self.show_header = False
self.verbose = True
self.title = "Data Explorer"
self.port = internal_tools.port_from_str(os.path.basename(__file__).split(".")[0])
# CSS path
self.home = os.path.expanduser("~")
self.css_path = os.path.join(self.home, "qim-app/app/static/css/gradio.css")
def clear(self):
"""Used to reset outputs with the clear button"""
return None
def create_interface(self):
with gr.Blocks(css=self.css_path) as gradio_interface:
gr.Markdown("# Data Explorer \n Quick insights from large datasets")
with gr.Row():
data_path = gr.Textbox(
value="/home/fima/Downloads/MarineGatropod_1.tif",
max_lines=1,
label="Path to the 3D volume",
)
with gr.Row(elem_classes=" w-128"):
btn_run = gr.Button(value="Load & Run", elem_classes="btn btn-run")
# Outputs
with gr.Row():
gr.Markdown("## Data overview")
with gr.Row():
data_summary = gr.Text(
label=None, show_label=False, elem_classes="monospace-box"
)
with gr.Column():
zslice_plot = gr.Plot(label="Z slice", elem_classes="rounded")
zpos = gr.Slider(
minimum=0, maximum=1, value=0.5, step=0.01, label="Z position"
)
with gr.Column():
yslice_plot = gr.Plot(label="Y slice", elem_classes="rounded")
ypos = gr.Slider(
minimum=0, maximum=1, value=0.5, step=0.01, label="Y position"
)
with gr.Column():
xslice_plot = gr.Plot(label="X slice", elem_classes="rounded")
xpos = gr.Slider(
minimum=0, maximum=1, value=0.5, step=0.01, label="X position"
)
with gr.Row(elem_classes="h-32"):
gr.Markdown()
with gr.Row(elem_classes="h-480"):
max_projection_plot = gr.Plot(
label="Z max projection", elem_classes="rounded"
)
min_projection_plot = gr.Plot(
label="Z min projection", elem_classes="rounded"
)
hist_plot = gr.Plot(label="Volume intensity histogram")
pipeline = Pipeline()
pipeline.verbose = self.verbose
session = gr.State([])
with gr.Row():
gr.Markdown("## Local thickness")
with gr.Row():
gr.Plot()
gr.Plot()
gr.Plot()
with gr.Row():
gr.Markdown("## Structure tensor")
with gr.Row():
gr.Plot()
gr.Plot()
gr.Plot()
### Gradio objects lists
# Inputs
inputs = [zpos, ypos, xpos]
# Outputs
outputs = [
data_summary,
zslice_plot,
yslice_plot,
xslice_plot,
max_projection_plot,
min_projection_plot,
]
projection_outputs = [session, max_projection_plot, min_projection_plot]
### Listeners
# Clear button
# for gr_obj in outputs:
# btn_clear.click(fn=self.clear, inputs=[], outputs=gr_obj)
# Run button
# fmt: off
btn_run.click(
fn=self.start_session, inputs=inputs, outputs=session).then(
fn=pipeline.process_input, inputs=[session, data_path], outputs=session).then(
fn=pipeline.show_summary_str, inputs=session, outputs=data_summary).then(
fn=pipeline.create_zslice_fig, inputs=session, outputs=zslice_plot).then(
fn=pipeline.create_yslice_fig, inputs=session, outputs=yslice_plot).then(
fn=pipeline.create_xslice_fig, inputs=session, outputs=xslice_plot).then(
fn=pipeline.create_projections_figs, inputs=session, outputs=projection_outputs).then(
fn=pipeline.show_summary_str, inputs=session, outputs=data_summary).then(
fn=pipeline.plot_vol_histogram, inputs=session, outputs=hist_plot)
zpos.release(
fn=self.update_zpos, inputs=[session, zpos], outputs=[session, zslice_plot]).then(
fn=pipeline.create_zslice_fig, inputs=session, outputs=zslice_plot,show_progress=False)
ypos.release(
fn=self.update_ypos, inputs=[session, ypos], outputs=[session, yslice_plot]).then(
fn=pipeline.create_yslice_fig, inputs=session, outputs=yslice_plot,show_progress=False)
xpos.release(
fn=self.update_xpos, inputs=[session, xpos], outputs=[session, xslice_plot]).then(
fn=pipeline.create_xslice_fig, inputs=session, outputs=xslice_plot,show_progress=False)
# fmt: on
return gradio_interface
def start_session(self, *args):
# Starts a new session dictionary
session = Session()
session.interface = "gradio"
session.zpos = args[0]
session.ypos = args[1]
session.xpos = args[2]
return session
def update_zpos(self, session, zpos):
session.zpos = zpos
session.zslice_from_zpos()
return session, gr.update(label=f"Z slice: {session.zslice}")
def update_ypos(self, session, ypos):
session.ypos = ypos
session.yslice_from_ypos()
return session, gr.update(label=f"Y slice: {session.yslice}")
def update_xpos(self, session, xpos):
session.xpos = xpos
session.xslice_from_xpos()
return session, gr.update(label=f"X slice: {session.xslice}")
def launch(self, default_port=False, quiet=True, **kwargs):
# Show header
if self.show_header:
apptools.gradio_header(self.title, self.port)
# Create gradio interfaces
interface = self.create_interface()
if self.verbose:
quiet = False
if default_port:
port = self.port
else:
port = None
interface.launch(server_port=port, quiet=quiet, **kwargs)
class Session:
def __init__(self):
self.interface = None
self.data_path = None
self.vol = None
self.zpos = 0.5
self.ypos = 0.5
self.xpos = 0.5
# Volume info
self.zsize = None
self.ysize = None
self.xsize = None
self.data_type = None
self.axes = None
self.last_modified = None
self.file_size = None
self.min_percentile = None
self.max_percentile = None
self.min_value = None
self.max_value = None
self.intensity_sum = None
self.mean_intensity = None
# Histogram
self.nbins = 32
def get_data_info(self):
# Open file
tif = tifffile.TiffFile(self.data_path)
first_slice = tif.pages[0]
# Get info
self.zsize = len(tif.pages)
self.ysize, self.xsize = first_slice.shape
self.data_type = first_slice.dtype
self.axes = tif.series[0].axes
self.last_modified = datetime.datetime.fromtimestamp(
os.path.getmtime(self.data_path)
).strftime("%Y-%m-%d %H:%M")
self.file_size = os.path.getsize(self.data_path)
# Close file
tif.close()
def create_summary_dict(self):
# Create dictionary
self.summary_dict = {
"Last modified": self.last_modified,
"File size": apptools.sizeof(self.file_size),
"Axes": self.axes,
"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):
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))
return self.zslice
def yslice_from_ypos(self):
self.yslice = int(self.ypos * (self.ysize - 1))
return self.yslice
def xslice_from_xpos(self):
self.xslice = int(self.xpos * (self.xsize - 1))
return self.xslice
class Pipeline:
def __init__(self):
self.figsize = 8 # Used for matplotlig figure size
self.display_saturation_percentile = 99
self.verbose = False
def process_input(self, *args):
session = args[0]
session.data_path = args[1]
# Get info from Tiff file
session.get_data_info()
session.create_summary_dict()
# Memory map data as a virtual stack
session.vol = tifffile.memmap(session.data_path)
if self.verbose:
print(ouf.br(3, return_str=True) + session.summary_str())
return session
def show_summary_str(self, session):
session.create_summary_dict()
return session.summary_str()
def create_zslice_fig(self, session):
slice_fig = self.create_slice_fig("z", session)
return slice_fig
def create_yslice_fig(self, session):
slice_fig = self.create_slice_fig("y", session)
return slice_fig
def create_xslice_fig(self, session):
slice_fig = self.create_slice_fig("x", session)
return slice_fig
def create_slice_fig(self, axis, session):
plt.close()
vol = session.vol
zslice = session.zslice_from_zpos()
yslice = session.yslice_from_ypos()
xslice = 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
else:
vmin = None
vmax = None
if axis == "z":
slice_fig = self._zslice_fig(vol, zslice, vmin=vmin, vmax=vmax)
if axis == "y":
slice_fig = self._yslice_fig(vol, yslice, vmin=vmin, vmax=vmax)
if axis == "x":
slice_fig = self._xslice_fig(vol, xslice, vmin=vmin, vmax=vmax)
return slice_fig
def _zslice_fig(self, vol, slice, **kwargs):
fig = self.create_img_fig(vol[slice, :, :], **kwargs)
return fig
def _yslice_fig(self, vol, slice, **kwargs):
fig = self.create_img_fig(vol[:, slice, :], **kwargs)
return fig
def _xslice_fig(self, vol, slice, **kwargs):
fig = self.create_img_fig(vol[:, :, slice], **kwargs)
return fig
def create_img_fig(self, img, **kwargs):
fig, ax = plt.subplots(figsize=(self.figsize, self.figsize))
ax.imshow(img, interpolation="nearest", **kwargs)
# Adjustments
ax.axis("off")
fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
return fig
def create_projections_figs(self, session):
vol = session.vol
# Run projections
max_projection, min_projection = self.get_projections(vol, session)
# Generate figures
max_projection_fig = self.create_img_fig(
max_projection,
vmin=session.min_percentile,
vmax=session.max_percentile,
)
min_projection_fig = self.create_img_fig(
min_projection,
vmin=session.min_percentile,
vmax=session.max_percentile,
)
return session, max_projection_fig, min_projection_fig
def get_projections(self, vol, session):
# 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
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(
min_projection, 100 - self.display_saturation_percentile
)
session.max_value = np.max(max_projection)
session.max_percentile = np.percentile(
max_projection, self.display_saturation_percentile
)
session.intensity_sum = intensity_sum
nvoxels = session.zsize * session.ysize * session.xsize
session.mean_intensity = intensity_sum / nvoxels
return max_projection, min_projection
def plot_vol_histogram(self, session):
vol_hist, bin_edges = self.vol_histogram(
session.vol, session.nbins, session.min_value, session.max_value
)
fig, ax = plt.subplots(figsize=(6, 4))
ax.bar(
bin_edges[:-1], vol_hist, width=np.diff(bin_edges), ec="white", align="edge"
)
# Adjustments
ax.spines["right"].set_visible(False)
ax.spines["top"].set_visible(False)
ax.spines["left"].set_visible(True)
ax.spines["bottom"].set_visible(True)
ax.set_yscale("log")
# fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
return fig
def vol_histogram(self, vol, nbins, min_value, max_value):
# Start histogram
vol_hist = np.zeros(nbins)
# Iterate over slices
for zslice in vol:
hist, bin_edges = np.histogram(
zslice, bins=nbins, range=(min_value, max_value)
)
vol_hist += hist
return vol_hist, bin_edges
if __name__ == "__main__":
app = AppInterface()
app.show_header = True
app.launch(server_name="0.0.0.0", show_error=True, default_port=False)
from .load import load
from .save import save
\ No newline at end of file
def load():
print ("hello from load")
\ No newline at end of file
def save():
print ("hello from save")
\ No newline at end of file
import socket
import hashlib
def mock_plot():
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
import numpy as np
import matplotlib
matplotlib.use("Agg")
fig = plt.figure(figsize=(5, 4))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
xx = np.arange(0, 2 * np.pi, 0.01)
ax.plot(xx, np.sin(xx))
return fig
def mock_write_file(path):
f = open(path, "w")
f.write("File created by apptools")
f.close()
def get_local_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(("192.255.255.255", 1))
IP = s.getsockname()[0]
except:
IP = "127.0.0.1"
finally:
s.close()
return IP
def port_from_str(s):
return int(hashlib.sha1(s.encode("utf-8")).hexdigest(), 16) % (10**4)
def gradio_header(title, port):
import outputformat as ouf
ouf.br(2)
details = [
f'{ouf.c(title, color="rainbow", cmap="cool", bold=True, return_str=True)}',
f"Using port {port}",
f"Running at {get_local_ip()}",
]
ouf.showlist(details, style="box", title="Starting gradio server")
def sizeof(num, suffix="B"):
for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]:
if abs(num) < 1024.0:
return f"{num:3.1f} {unit}{suffix}"
num /= 1024.0
return f"{num:.1f} Y{suffix}"
aiofiles==23.1.0
aiohttp==3.8.4
aiosignal==1.3.1
altair==5.0.0
anyio==3.6.2
async-timeout==4.0.2
attrs==23.1.0
certifi==2023.5.7
charset-normalizer==3.1.0
click==8.1.3
contourpy==1.0.7
cycler==0.11.0
edt==2.3.1
fastapi==0.95.1
ffmpy==0.3.0
filelock==3.12.0
fonttools==4.39.4
frozenlist==1.3.3
fsspec==2023.5.0
gradio==3.30.0
gradio_client==0.2.4
h11==0.14.0
httpcore==0.17.0
httpx==0.24.0
huggingface-hub==0.14.1
idna==3.4
Jinja2==3.1.2
jsonschema==4.17.3
kiwisolver==1.4.4
linkify-it-py==2.0.2
localthickness==0.1.2
markdown-it-py==2.2.0
MarkupSafe==2.1.2
matplotlib==3.7.1
mdit-py-plugins==0.3.3
mdurl==0.1.2
multidict==6.0.4
numpy==1.24.3
orjson==3.8.12
outputformat==0.1.3
packaging==23.1
pandas==2.0.1
Pillow==9.5.0
plotly==5.14.1
pydantic==1.10.7
pydub==0.25.1
Pygments==2.15.1
pyparsing==3.0.9
pyrsistent==0.19.3
python-dateutil==2.8.2
python-multipart==0.0.6
pytz==2023.3
PyYAML==6.0
requests==2.30.0
scipy==1.10.1
semantic-version==2.10.0
six==1.16.0
sniffio==1.3.0
starlette==0.26.1
tenacity==8.2.2
tifffile==2023.4.12
toolz==0.12.0
tqdm==4.65.0
typing_extensions==4.5.0
tzdata==2023.3
uc-micro-py==1.0.2
urllib3==2.0.2
uvicorn==0.22.0
websockets==11.0.3
yarl==1.9.2
setup.py 0 → 100644
from setuptools import setup, find_packages
# Read the contents of your README file
with open("README.md", "r", encoding="utf-8") as f:
long_description = f.read()
setup(
name="qim",
version="0.1.0",
author="Felipe Delestro",
author_email="fima@dtu.dk",
description="QIM tools and user interfaces",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://lab.compute.dtu.dk/QIM/qim",
packages=find_packages(),
classifiers=[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Development Status :: 1 - Planning",
"Intended Audience :: Education",
"Intended Audience :: Science/Research",
"Natural Language :: English",
"Operating System :: OS Independent",
"Topic :: Scientific/Engineering :: Image Processing",
"Topic :: Scientific/Engineering :: Visualization",
"Topic :: Software Development :: User Interfaces",
],
python_requires=">=3.6",
install_requires=open("requirements.txt").readlines(),
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment