Skip to content

Commit

Permalink
Add prostate volume
Browse files Browse the repository at this point in the history
  • Loading branch information
Lightbridge-KS committed Jul 12, 2024
1 parent 0674309 commit 2b14410
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 5 deletions.
33 changes: 33 additions & 0 deletions calc/vol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Ellipsoid Volume
from typing import List

def prostate_vol(x: List[float]):
"""Calculate prostate volume (ml) and diagnosis"""
v = ellipsoid_list(x)
if v < 25:
dx = "Normal"
elif v == 25:
dx = "Normal or Prominent"
elif v < 40:
dx = "Prominent"
elif v == 40:
dx = "Prominent or Enlarged"
else:
dx = "Enlarged"

return f"Prostate vol: {round(v, 2)} ml ({dx})"



def ellipsoid(d1, d2, d3):
"""Calculate ellipsoid volume from 3 perpendicular **diameters**"""
import math
volume = (4/3) * math.pi * d1/2 * d2/2 * d3/2
return volume

def ellipsoid_list(x: List[float]):
"""Calculate ellipsoid volume from 3 perpendicular **diameters** (List input)"""
try:
return ellipsoid(*x)
except TypeError:
raise TypeError(f"{x} must be a list of three floats")
120 changes: 119 additions & 1 deletion dev/calc-dev.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Mean Calc"
"### Mean Calc"
]
},
{
Expand Down Expand Up @@ -52,6 +52,124 @@
"print(calc_mean([1.1, 1.2]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Prostate Vol"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"def prostate_vol(x: List[float]):\n",
" \"\"\"Calculate prostate volume (ml) and diagnosis\"\"\"\n",
" v = ellipsoid_list(x)\n",
" if v < 25:\n",
" dx = \"Normal\"\n",
" elif v == 25:\n",
" dx = \"Normal or Prominent\"\n",
" elif v < 40:\n",
" dx = \"Prominent\"\n",
" elif v == 40:\n",
" dx = \"Prominent or Enlarged\"\n",
" else:\n",
" dx = \"Enlarged\"\n",
" \n",
" print(f\"Prostate vol: {round(v, 2)} ml ({dx})\")"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"def ellipsoid(d1, d2, d3):\n",
" \"\"\"Calculate ellipsoid volume from 3 perpendicular **diameters**\"\"\"\n",
" import math\n",
" volume = (4/3) * math.pi * d1/2 * d2/2 * d3/2\n",
" return volume\n",
"\n",
"def ellipsoid_list(x: List[float]):\n",
" try: \n",
" return ellipsoid(*x)\n",
" except TypeError:\n",
" raise TypeError(f\"{x} must be a list of three floats\")"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Prostate vol: 3.14 ml (Normal)\n"
]
}
],
"source": [
"v1 = [1, 2, 3]\n",
"ellipsoid(*v1)\n",
"prostate_vol(v1)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"ename": "TypeError",
"evalue": "[1, 'A', 'B'] must be a list of three floats",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[29], line 9\u001b[0m, in \u001b[0;36mellipsoid_list\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m: \n\u001b[0;32m----> 9\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mellipsoid\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 10\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n",
"Cell \u001b[0;32mIn[29], line 4\u001b[0m, in \u001b[0;36mellipsoid\u001b[0;34m(d1, d2, d3)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mmath\u001b[39;00m\n\u001b[0;32m----> 4\u001b[0m volume \u001b[38;5;241m=\u001b[39m \u001b[43m(\u001b[49m\u001b[38;5;241;43m4\u001b[39;49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mmath\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpi\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[43md1\u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m \u001b[49m\u001b[43md2\u001b[49m\u001b[38;5;241m/\u001b[39m\u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m d3\u001b[38;5;241m/\u001b[39m\u001b[38;5;241m2\u001b[39m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m volume\n",
"\u001b[0;31mTypeError\u001b[0m: can't multiply sequence by non-int of type 'float'",
"\nDuring handling of the above exception, another exception occurred:\n",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[35], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# ellipsoid_list([\"A\", 1, 2])\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;66;03m# prostate_vol([1, 2, 3, 4])\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[43mprostate_vol\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mA\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mB\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n",
"Cell \u001b[0;32mIn[30], line 3\u001b[0m, in \u001b[0;36mprostate_vol\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mprostate_vol\u001b[39m(x: List[\u001b[38;5;28mfloat\u001b[39m]):\n\u001b[1;32m 2\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Calculate prostate volume (ml) and diagnosis\"\"\"\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m v \u001b[38;5;241m=\u001b[39m \u001b[43mellipsoid_list\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m v \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m25\u001b[39m:\n\u001b[1;32m 5\u001b[0m dx \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNormal\u001b[39m\u001b[38;5;124m\"\u001b[39m\n",
"Cell \u001b[0;32mIn[29], line 11\u001b[0m, in \u001b[0;36mellipsoid_list\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m ellipsoid(\u001b[38;5;241m*\u001b[39mx)\n\u001b[1;32m 10\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[0;32m---> 11\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mx\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m must be a list of three floats\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
"\u001b[0;31mTypeError\u001b[0m: [1, 'A', 'B'] must be a list of three floats"
]
}
],
"source": [
"# ellipsoid_list([\"A\", 1, 2])\n",
"# prostate_vol([1, 2, 3, 4])\n",
"prostate_vol([1, \"A\", \"B\"])"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3.141592653589793"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ellipsoid_list(v1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down
4 changes: 2 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import datetime
from flet import Container, Column, Row, ResponsiveRow, Page

from module import AppDesignCT, AppSpineHtLoss, AppMean
from module import AppDesignCT, AppSpineHtLoss, AppMean, AppVol
from designcter._utils import dash_if_blank


Expand Down Expand Up @@ -37,7 +37,7 @@ def change_tab(e):
)

tab_1 = AppDesignCT()
tab_2 = ft.Column(controls=[AppMean(), AppSpineHtLoss()])
tab_2 = ft.Column(controls=[AppMean(), AppVol(), AppSpineHtLoss()])
## Default
tab_1.visible = True; tab_2.visible = False
#ft.Text("Tab 2",size=30,visible=False)
Expand Down
3 changes: 2 additions & 1 deletion module/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .designct_app import AppDesignCT
from .mean_app import AppMean
from .spine_ht_loss_app import AppSpineHtLoss
from .spine_ht_loss_app import AppSpineHtLoss
from .vol_app import AppVol
3 changes: 2 additions & 1 deletion module/man.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
class Manual:
mean_app = f"""Use spaces or comma to separate numbers (e.g. 1.1 1.2)"""
spine_ht_loss_app = f"""Input height in centimeter and use two values to calculate mean, separated by spaces or comma (e.g. 10 12)"""
spine_ht_loss_app = f"""Input height in centimeter and use two values to calculate mean, separated by spaces or comma (e.g. 10 12)"""
vol_app = f"""Input perpendicular diameters (cm) in 3 planes, separated by spaces or comma (e.g. 4.4 4.5 4.6)"""
64 changes: 64 additions & 0 deletions module/vol_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import flet as ft
from flet import Container, Column, Row, ResponsiveRow
import pyperclip

from calc.vol import prostate_vol
from calc._utils import parse_str_to_num_or_list, read_markdown_file
from module.man import Manual

class AppVol(ft.UserControl):
def __init__(self):
super().__init__()

## Input Diameters
self.input_numbers_text = ft.TextField(
label="Diameters in 3 planes (cm)", hint_text="e.g. 4.4 4.5 4.6"
)

# Button
self.btn = ft.ElevatedButton(text="Generate", on_click=self.button_gen_clicked)
self.btn_copy = ft.IconButton(icon=ft.icons.CONTENT_COPY, icon_size=20, tooltip="Copy output", on_click=self.button_cp_clicked)

# Output text
txt_size = 14 # 14
self.output_text_field = ft.TextField(label="Prostate Volume", value="", multiline=True, read_only=False, text_size=txt_size)

def build(self):
rr = ResponsiveRow(
controls=[
ft.Text("Prostate Volume", theme_style=ft.TextThemeStyle.TITLE_LARGE),
Column(col={"sm": 6},
controls = [
self.input_numbers_text,
# Manual
ft.Text(Manual.vol_app, theme_style = ft.TextThemeStyle.BODY_SMALL, color=ft.colors.GREY),
# ft.Markdown(Manual.mean_app, selectable=True)
], alignment=ft.MainAxisAlignment.START),
Column(col={"sm": 6},
controls = [
self.output_text_field,
Row([self.btn, self.btn_copy], alignment=ft.MainAxisAlignment.START),
], alignment=ft.MainAxisAlignment.START)
]
)
lv = ft.ListView(controls=[rr], expand=1, spacing=5, padding=10, auto_scroll=False)
return lv

def button_cp_clicked(self, e):
pyperclip.copy(self.output_text_field.value)

def button_gen_clicked(self, e):
self._log()
self.output_text_field.value = self.calc()
self.output_text_field.focus()
self.output_text_field.update()

def _log(self):
print("Btn clicked")
print(f"Input: {self.input_numbers_text.value}")
print(self.calc())

def calc(self):
numbers = parse_str_to_num_or_list(self.input_numbers_text.value)
mean = prostate_vol(numbers)
return mean

0 comments on commit 2b14410

Please sign in to comment.