Skip to content

Commit b67e00d

Browse files
committedJan 5, 2022
upgrade to PyQt5 and improve
1 parent 261f799 commit b67e00d

File tree

4 files changed

+515
-0
lines changed

4 files changed

+515
-0
lines changed
 

‎PyQtMapManager/readme.md

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## Front end to MaManager using PyQt5
2+
3+
This is a basic prototype. It leaves a lot to be desired.
4+
5+
## Install
6+
7+
1) Make a virtual environment
8+
9+
```
10+
cd PyQtMapManager
11+
python -m venv mm_env
12+
13+
source mm_env/bin/activate
14+
```
15+
16+
2) Install backend MapManager
17+
18+
```
19+
# in the `PyQtMapManager` folder
20+
pip install -e ../.
21+
```
22+
23+
3) Install PyQtMapManager
24+
25+
```
26+
# in the `PyQtMapManager` folder
27+
pip install -r requirements.txt
28+
```
29+
30+
## Run
31+
32+
```
33+
python main.py
34+
```

‎PyQtMapManager/requirements.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
qdarkstyle
2+
matplotlib
3+
pyqt5

‎examples/Download BIL data.ipynb

+288
Large diffs are not rendered by default.

‎pymapmanager/bilLoader.py

+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
'''
2+
Author: Robert H Cudmore
3+
Date: 20211023
4+
5+
Load bil .tif images and .txt files. Provide function to slice 3D stacks once loaded.
6+
7+
ToDo: Add a flask (or fast api) wrapper
8+
9+
'''
10+
11+
import os
12+
import requests
13+
import io
14+
import json
15+
#import numpy as np
16+
import pandas as pd # to load .txt files into dataframe
17+
import tifffile # to load tif files from requests response 'content'
18+
from bs4 import BeautifulSoup # used to parse html response from bil
19+
20+
class bilLoader():
21+
def __init__(self, bilID : str, loadFrom = 'remote'):
22+
# check we have a 16-digit ID
23+
if len(bilID) != 16:
24+
#logger.error()
25+
print('error: bil id must be 16-digits.')
26+
27+
self._bilUrl = 'https://download.brainimagelibrary.org'
28+
self._bilID = bilID
29+
self._loadFrom = loadFrom
30+
31+
32+
@property
33+
def bilUrl(self):
34+
"""
35+
Return base bil url.
36+
Usually is https://download.brainimagelibrary.org
37+
"""
38+
return self._bilUrl
39+
40+
@property
41+
def bilID(self):
42+
"""
43+
Return 16-digit bil id.
44+
"""
45+
return self._bilID
46+
47+
@property
48+
def bilPath(self):
49+
return self._getPathFromID(self.bilID)
50+
51+
def getRootFolders(self):
52+
"""
53+
Return a list of folder names associated with a bil ID
54+
"""
55+
folder = self.bilPath # /ab/cd/
56+
folder = self._urljoin(folder, self.bilID)
57+
return self._getLinks(folder)
58+
59+
def getFilesAndFolders(self, folder: str):
60+
"""
61+
Return a list of file and folder names.
62+
Folders will end in '/'
63+
"""
64+
fullFolder = self.bilPath # /ab/cd/
65+
fullFolder = self._urljoin(fullFolder, self.bilID)
66+
fullFolder = self._urljoin(fullFolder, folder)
67+
return self._getLinks(fullFolder)
68+
69+
def getAllObjects(self):
70+
"""
71+
Get the names of all objects from a bil id
72+
73+
Returns:
74+
A list of (dict, str), if str then it is usally the filename
75+
If an entry is a dist then it is a recursive list of filename
76+
"""
77+
folderDict = {}
78+
rootFolderList = self.getRootFolders()
79+
for rootFolder in rootFolderList:
80+
folderDict[rootFolder] = []
81+
objList = self.getFilesAndFolders(rootFolder)
82+
for obj in objList:
83+
if obj.endswith('/'):
84+
innerFolder = self._urljoin(rootFolder, obj)
85+
recursiveObj = self.getFilesAndFolders(innerFolder)
86+
recursiveDict = {}
87+
recursiveDict[innerFolder] = recursiveObj
88+
folderDict[rootFolder].append(recursiveDict)
89+
else:
90+
folderDict[rootFolder].append(obj)
91+
92+
#
93+
return folderDict
94+
95+
def _getPathFromID(self, id: str):
96+
"""
97+
Get /ab/cd/ path from first 4-digits of 16-digit bilID abcdxxxxxxxxxxxx
98+
"""
99+
firstDir = id[0:2]
100+
secondDir = id[2:4]
101+
thepath = self._urljoin(firstDir, secondDir)
102+
return thepath
103+
104+
def _urlFromFolder(self, folder: str):
105+
return self._urljoin(self.bilUrl, folder)
106+
107+
def _getLinks(self, folder, verbose=False):
108+
"""
109+
Get a list of <A HREF> links from bil (e.g. a list of files in url).
110+
111+
Args:
112+
folder (str): url folder postfix like /ab/cd/
113+
114+
Returns:
115+
List of objects, each object i either a folder or a file.
116+
Folders end in '/'
117+
"""
118+
119+
url = self._urlFromFolder(folder)
120+
121+
if verbose:
122+
print('_getLinks() url:', url)
123+
124+
r = requests.get(url)
125+
soup = BeautifulSoup(r.content, 'html.parser')
126+
127+
# always ignore some links
128+
ignoreList = ['./', '../']
129+
130+
# specific to cudmore data
131+
ignoreTuple = ('.finished', '.master')
132+
133+
fileList = []
134+
135+
linkList = soup.find_all('a')
136+
for link in linkList:
137+
# link is type <class 'bs4.element.Tag'>
138+
href = link.get('href')
139+
if href in ignoreList:
140+
continue
141+
142+
# specific to cudmore data
143+
if href.endswith(ignoreTuple):
144+
continue
145+
146+
fileList.append(href)
147+
#
148+
return fileList
149+
150+
def _urljoin(self, *args):
151+
"""
152+
Joins given arguments into an url. Trailing but not leading slashes are
153+
stripped for each argument.
154+
"""
155+
156+
return "/".join(map(lambda x: str(x).rstrip('/'), args))
157+
158+
def _old_printResp(self, r):
159+
"""
160+
Print out a requests response
161+
"""
162+
print(f' status_code: {r.status_code}')
163+
164+
# text will often be raw html, parse with BeautifulSoup
165+
#print(f' text: {r.text}')
166+
167+
print(f' encoding: {r.encoding}')
168+
print(f" headers['content-type']: {r.headers['content-type']}")
169+
170+
print(' fetching content ...')
171+
content = r.content
172+
print(' ... got content')
173+
174+
print(f' len(content): {len(content)}')
175+
print(f' type(content): {type(content)}')
176+
177+
if __name__ == '__main__':
178+
bilID = 'd901fb2108458eca'
179+
bl = bilLoader(bilID)
180+
print('bilID:', bl.bilID)
181+
print('bilPath:', bl.bilPath)
182+
183+
#rootFolders = bl.getRootFolders()
184+
#print('getRootFolders():', rootFolders)
185+
186+
objDict = bl.getAllObjects()
187+
print('objDict:')
188+
print(json.dumps(objDict, indent=4))
189+
190+
# parse the results and plot a line

0 commit comments

Comments
 (0)
Please sign in to comment.