Skip to content

Commit b0474e1

Browse files
authored
Merge pull request #22 from tldr-group/cleanup
merge Cleanup onto Dev
2 parents 4d704cd + e5b5c95 commit b0474e1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3626
-1769
lines changed

.github/workflows/tests.yaml

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# This workflow will install Python dependencies, run tests and lint with a single version of Python
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3+
4+
name: Python application
5+
6+
on:
7+
push:
8+
branches: [ "cleanup" ]
9+
pull_request:
10+
branches: [ "main", ]
11+
12+
permissions:
13+
contents: read
14+
15+
jobs:
16+
build:
17+
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- uses: actions/checkout@v3
22+
- name: Set up Python 3.10
23+
uses: actions/setup-python@v3
24+
with:
25+
python-version: "3.10"
26+
- name: Install dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install -r requirements.txt
30+
pip install -e .
31+
# commented out for now until refactoring of experiments done
32+
#- name: Lint with flake8
33+
# run: |
34+
# # stop the build if there are Python syntax errors or undefined names
35+
# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
36+
# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
37+
# flake8 . --count --exit-zero --max-complexity=15 --max-line-length=127 --statistics --ignore=E203
38+
- name: Test with unittest
39+
run: |
40+
python tests/tests.py

.gitignore

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ fig2 copy.py
1111
*.pdf
1212
*.png
1313
*.npy
14+
1415
.vscode
1516
frontend/node_modules
1617
frontend/dist
17-
*.kra
18+
*.kra
19+
deploy*/
20+
deploy.sh
21+
deploy.zip
22+
23+
tests/tmp.py

MANIFEST.in

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
include requirements.txt
2+
include LICENSE
3+
include README.md
4+
5+
recursive-exclude * __pycache__
6+
recursive-exclude * *.py[co]
7+
recursive-exclude * *old*

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Representativity
2+
3+
You take a micrograph of a material. You segment it, and measure the phase fractions. How sure are you that the phase fraction of the whole material is close to your measurements?
4+
5+
```
6+
pip install -e .
7+
```
8+
9+
10+
Questions:
11+
- Website name (isitrepresentative.com) (howrepresentativeismysample.com)
12+
- model err problem
13+
- refactoring
14+
- cls for squares
15+
- update readme/example notebook
16+
- licnece: todo

frontend/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.5.0",
44
"license": "MIT",
55
"scripts": {
6-
"build": "yarn run clean-dist && webpack --config=configs/webpack/prod.js && mv dist/*.wasm dist/js",
6+
"build": "yarn run clean-dist && webpack --config=configs/webpack/prod.js",
77
"clean-dist": "rimraf dist/*",
88
"lint": "eslint './src/**/*.{js,ts,tsx}' --quiet",
99
"start": "yarn run start-dev",
@@ -52,7 +52,7 @@
5252
"webpack-merge": "^5.8.0"
5353
},
5454
"dependencies": {
55-
"bootstrap": "^5.2.3",
55+
"bootstrap": "5.2.3",
5656
"pako": "^2.1.0",
5757
"react": "18.2.0",
5858
"react-bootstrap": "2.7.4",

frontend/src/App.tsx

+124-19
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,47 @@
11
import React, { useContext, useEffect, useRef, useState } from "react";
2-
import AppContext, { ImageLoadInfo, AnalysisInfo } from "./components/interfaces";
2+
import AppContext, { ImageLoadInfo, AnalysisInfo, IR_LIMIT_PX } from "./components/interfaces";
33

44
import Topbar from "./components/Topbar";
55
import DragDrop from "./components/DragDrop";
66
import PreviewCanvas from "./components/Canvas";
7-
import Menu from "./components/Modals";
7+
import NormalSlider from "./components/NormalSlider";
8+
import { Menu } from "./components/Menu";
9+
import { ErrorMessage, CLSModal, MoreInfo } from "./components/Popups"
810

911
import { loadFromTIFF, loadFromImage } from "./components/imageLogic";
1012

1113
import "./assets/scss/App.scss";
1214
import 'bootstrap/dist/css/bootstrap.min.css';
1315

16+
//const PATH = "http://127.0.0.1:5000";
17+
const PATH = "https://samba-segment.azurewebsites.net";
18+
//const PATH = "http://localhost:7071/api";
19+
//const PATH = "https://representative.azurewebsites.net/api"
20+
const PF_ENDPOINT = PATH + "/phasefraction"
21+
//const PF_ENDPOINT = "https://representativity.azurewebsites.net/phasefraction"
22+
23+
//const REPR_ENDPOINT = PATH + "/repr";
24+
const REPR_ENDPOINT = PATH + "/repr";
25+
1426
const MAX_FILE_SIZE_BYTES = 1024 * 1024 * 500; // 500MB
1527

1628
const App = () => {
1729
const {
1830
imageInfo: [imageInfo, setImageInfo],
1931
previewImg: [previewImg, setPreviewImg],
32+
selectedPhase: [selectedPhase, setSelectedPhase],
33+
selectedConf: [selectedConf, setSelectedConf],
34+
errVF: [errVF, setErrVF],
2035
targetL: [targetL, setTargetL],
36+
pfB: [, setPfB],
37+
accurateFractions: [accurateFractions, setAccurateFractions],
2138
analysisInfo: [, setAnalysisInfo],
2239
menuState: [menuState, setMenuState],
40+
errorState: [errorState, setErrorState],
41+
showWarning: [showWarning, setShowWarning],
2342
} = useContext(AppContext)!
2443

44+
2545
const appLoadFile = async (file: File) => {
2646
const reader = new FileReader();
2747
const extension = file.name.split('.').pop()?.toLowerCase();
@@ -34,14 +54,14 @@ const App = () => {
3454
} else if (isPNGJPG) {
3555
reader.readAsDataURL(file);
3656
} else {
37-
console.log(`Unsupported file format .${extension}`);
57+
setErrorState({ msg: `Unsupported file format .${extension}`, stackTrace: "" })
3858
return;
3959
};
4060

4161
reader.onload = async () => {
4262
let result: ImageLoadInfo | null = null;
4363
if (file.size > MAX_FILE_SIZE_BYTES) {
44-
console.log(`File .${file.size / (1000 * 1000)}MB greater than max size (500MB)`);
64+
setErrorState({ msg: `File too large!`, stackTrace: `File .${file.size / (1000 * 1000)}MB greater than max size (500MB)` })
4565
return;
4666
}
4767

@@ -53,40 +73,125 @@ const App = () => {
5373
};
5474
console.log(result);
5575

56-
if (result?.segmented == false) {
57-
console.log('error: unsegmented');
76+
if (result == null) {
77+
setErrorState({
78+
msg: "Failed to load data",
79+
stackTrace: ""
80+
});
81+
return;
82+
}
83+
84+
if (result.segmented == false) {
85+
setErrorState({
86+
msg: "Data is unsegmented - try using our web segmentation tool, SAMBA (https://www.sambasegment.com/)",
87+
stackTrace: "Number of unique values > 6"
88+
});
89+
return;
5890
} else {
59-
result!.file = file;
91+
if (result.height < 200 || result.width < 200 || (result.depth < 200 && result.depth > 1)) {
92+
setShowWarning("size");
93+
}
94+
95+
requestPhaseFraction(file);
96+
result.file = file;
6097
setImageInfo(result);
61-
setPreviewImg(result!.previewImg);
98+
setPreviewImg(result.previewImg);
6299
setMenuState('phase');
63100
}
64101
};
65102
}
66103

67-
useEffect(() => { // TODO: fetch from API instead
68-
if (menuState === 'processing') {
69-
setMenuState('conf_result');
70-
setTargetL(4 * imageInfo?.width!);
104+
const requestPhaseFraction = async (file: File) => {
105+
try {
106+
const formData = new FormData();
107+
formData.append('userFile', file);
108+
//formData.append('phaseVal', String(selectedPhaseValue));
109+
const resp = await fetch(PF_ENDPOINT, { method: 'POST', body: formData });
110+
const obj = await resp.json();
111+
const fractions = obj["phase_fractions"] as { [val: number]: number };
112+
setAccurateFractions(fractions);
113+
} catch (e) {
114+
const error = e as Error;
115+
setErrorState({ msg: "Couldn't fetch phase fractions: data wrong or server down.", stackTrace: error.toString() });
116+
}
117+
}
118+
119+
const requestRepr = async () => {
120+
try {
121+
const info = imageInfo!
122+
123+
const formData = new FormData();
124+
formData.append('userFile', info.file!);
125+
formData.append('selected_phase', String(info.phaseVals[selectedPhase - 1]));
126+
formData.append('selected_conf', String(selectedConf));
127+
formData.append('selected_err', String(errVF));
128+
129+
const resp = await fetch(REPR_ENDPOINT, { method: 'POST', body: formData });
130+
const obj = await resp.json();
131+
132+
const absErr: number = obj["abs_err"]
133+
134+
console.log(obj)
135+
136+
setMenuState('conf_result_full');
71137
setAnalysisInfo({
72-
integralRange: 1,
138+
integralRange: obj["cls"],
73139
z: 1,
74-
percentageErr: 5,
75-
absError: 5 * 0.45,
76-
lForDefaultErr: 4 * imageInfo?.width!,
77-
vf: 0.45
140+
stdModel: obj["std_model"],
141+
percentageErr: obj["percent_err"],
142+
absError: absErr,
143+
lForDefaultErr: obj["l"],
144+
vf: 1,
145+
pf: obj['pf_1d'],
146+
cumSumSum: obj["cum_sum_sum"]
78147
})
148+
149+
const vals = imageInfo?.phaseVals!
150+
const phaseFrac = accurateFractions![vals[selectedPhase - 1]]
151+
setPfB([phaseFrac - absErr, phaseFrac + absErr])
152+
153+
if (obj["cls"] > IR_LIMIT_PX) { setShowWarning("cls") }
154+
const minSide = Math.min(imageInfo?.width!, imageInfo?.height!)
155+
if (obj["l"] < minSide) { setShowWarning("over") }
156+
157+
setTargetL(obj["l"]);
158+
} catch (e) {
159+
const error = e as Error;
160+
setErrorState({ msg: "Couldn't determine representativity: data wrong or server down.", stackTrace: error.toString() });
161+
}
162+
}
163+
164+
const reset = () => {
165+
setMenuState('hidden');
166+
setPreviewImg(null);
167+
setImageInfo(null);
168+
setAnalysisInfo(null);
169+
setTargetL(null);
170+
setAccurateFractions(null);
171+
setPreviewImg(null);
172+
setSelectedPhase(0);
173+
setErrVF(5);
174+
setSelectedConf(95);
175+
}
176+
177+
useEffect(() => { // TODO: fetch from API instead
178+
if (menuState === 'processing') {
179+
requestRepr();
79180
}
80181
}, [menuState])
81182

82183
return (
83184
<div className={`w-full h-full`}>
84-
<Topbar></Topbar>
185+
<Topbar loadFromFile={appLoadFile} reset={reset}></Topbar>
85186
<div className={`flex`} style={{ margin: '1.5%' }} > {/*Canvas div on left, sidebar on right*/}
86187
{!previewImg && <DragDrop loadFromFile={appLoadFile} />}
87188
{previewImg && <PreviewCanvas />}
189+
{false && <NormalSlider />}
88190
</div>
89-
<Menu></Menu>
191+
<Menu />
192+
<ErrorMessage />
193+
{showWarning != "" && <CLSModal />}
194+
<MoreInfo />
90195
</div>
91196
);
92197
};

0 commit comments

Comments
 (0)