Various bug fixes

This commit is contained in:
Landon Wark
2024-03-07 14:26:29 -06:00
parent b466cb61d2
commit d0418ebc9e
7 changed files with 80 additions and 37 deletions

View File

@@ -1,3 +1,4 @@
- [x] Fix cropping of gel image.
- [ ] Create Tips ... *sigh*. - [ ] Create Tips ... *sigh*.
- [x] Create platemap image from html for export to pdf. - [x] Create platemap image from html for export to pdf.
- [x] Move plate map maker to submission. - [x] Move plate map maker to submission.

Binary file not shown.

View File

@@ -9,7 +9,7 @@ from tempfile import TemporaryDirectory
from reportlab.graphics.barcode import createBarcodeImageInMemory from reportlab.graphics.barcode import createBarcodeImageInMemory
from reportlab.graphics.shapes import Drawing from reportlab.graphics.shapes import Drawing
from reportlab.lib.units import mm from reportlab.lib.units import mm
from operator import attrgetter from operator import attrgetter, itemgetter
from pprint import pformat from pprint import pformat
from . import Reagent, SubmissionType, KitType, Organization from . import Reagent, SubmissionType, KitType, Organization
from sqlalchemy import Column, String, TIMESTAMP, INTEGER, ForeignKey, JSON, FLOAT, case from sqlalchemy import Column, String, TIMESTAMP, INTEGER, ForeignKey, JSON, FLOAT, case
@@ -1349,11 +1349,13 @@ class WastewaterArtic(BasicSubmission):
Returns: Returns:
dict: Updated sample dictionary dict: Updated sample dictionary
""" """
from backend.validators import RSLNamer
input_dict = super().parse_info(input_dict) input_dict = super().parse_info(input_dict)
df = xl.parse("First Strand List", header=None) df = xl.parse("First Strand List", header=None)
plates = [] plates = []
for row in [8,9,10]: for row in [8,9,10]:
plates.append(dict(plate=df.iat[row-1, 2], start_sample=df.iat[row-1, 3])) plate_name = RSLNamer(df.iat[row-1, 2]).parsed_name
plates.append(dict(plate=plate_name, start_sample=df.iat[row-1, 3]))
input_dict['source_plates'] = plates input_dict['source_plates'] = plates
return input_dict return input_dict
@@ -1373,6 +1375,16 @@ class WastewaterArtic(BasicSubmission):
# Because generate_sample_object needs the submitter_id and the artic has the "({origin well})" # Because generate_sample_object needs the submitter_id and the artic has the "({origin well})"
# at the end, this has to be done here. No moving to sqlalchemy object :( # at the end, this has to be done here. No moving to sqlalchemy object :(
input_dict['submitter_id'] = re.sub(r"\s\(.+\)\s?$", "", str(input_dict['submitter_id'])).strip() input_dict['submitter_id'] = re.sub(r"\s\(.+\)\s?$", "", str(input_dict['submitter_id'])).strip()
try:
input_dict['ww_processing_num'] = input_dict['sample_name_(lims)']
del input_dict['sample_name_(lims)']
except KeyError:
logger.error(f"Unable to set ww_processing_num for sample {input_dict['submitter_id']}")
try:
input_dict['ww_full_sample_id'] = input_dict['sample_name_(ww)']
del input_dict['sample_name_(ww)']
except KeyError:
logger.error(f"Unable to set ww_processing_num for sample {input_dict['submitter_id']}")
if "ENC" in input_dict['submitter_id']: if "ENC" in input_dict['submitter_id']:
input_dict['submitter_id'] = cls.en_adapter(input_str=input_dict['submitter_id']) input_dict['submitter_id'] = cls.en_adapter(input_str=input_dict['submitter_id'])
return input_dict return input_dict
@@ -1642,6 +1654,7 @@ class WastewaterArtic(BasicSubmission):
output.append(dicto) output.append(dicto)
# else: # else:
# output = super().adjust_to_dict_samples(backup=False) # output = super().adjust_to_dict_samples(backup=False)
return output return output
def custom_context_events(self) -> dict: def custom_context_events(self) -> dict:
@@ -1751,7 +1764,7 @@ class BasicSample(BaseClass):
sample['Submitter ID'] = self.submitter_id sample['Submitter ID'] = self.submitter_id
sample['Sample Type'] = self.sample_type sample['Sample Type'] = self.sample_type
if full_data: if full_data:
sample['submissions'] = [item.to_sub_dict() for item in self.sample_submission_associations] sample['submissions'] = sorted([item.to_sub_dict() for item in self.sample_submission_associations], key=itemgetter('submitted_date'))
return sample return sample
def set_attribute(self, name:str, value): def set_attribute(self, name:str, value):
@@ -1857,19 +1870,6 @@ class BasicSample(BaseClass):
template = env.get_template("basicsample_details.html") template = env.get_template("basicsample_details.html")
return base_dict, template return base_dict, template
def show_details(self, obj):
"""
Creates Widget for showing sample details.
Args:
obj (_type_): parent widget
"""
logger.debug("Hello from details")
from frontend.widgets.sample_details import SampleDetails
dlg = SampleDetails(parent=obj, samp=self)
if dlg.exec():
pass
@classmethod @classmethod
@setup_lookup @setup_lookup
def query(cls, def query(cls,
@@ -2126,6 +2126,7 @@ class SubmissionSampleAssociation(BaseClass):
sample['Well'] = None sample['Well'] = None
sample['Plate Name'] = self.submission.rsl_plate_num sample['Plate Name'] = self.submission.rsl_plate_num
sample['Positive'] = False sample['Positive'] = False
sample['submitted_date'] = self.submission.submitted_date
return sample return sample
def to_hitpick(self) -> dict|None: def to_hitpick(self) -> dict|None:

View File

@@ -44,9 +44,11 @@ class GelBox(QDialog):
pg.setConfigOptions(antialias=True) pg.setConfigOptions(antialias=True)
# creating image view object # creating image view object
self.imv = pg.ImageView() self.imv = pg.ImageView()
img = np.array(Image.open(self.img_path).rotate(-90).transpose(Image.FLIP_LEFT_RIGHT)) # Create image.
self.imv.setImage(img, scale=None)#, xvals=np.linspace(1., 3., data.shape[0])) # For some reason, ImageView wants to flip the image, so we have to rotate and flip the array first.
# Using the Image.rotate function results in cropped image.
img = np.flip(np.rot90(np.array(Image.open(self.img_path)),1),0)
self.imv.setImage(img)
layout = QGridLayout() layout = QGridLayout()
layout.addWidget(QLabel("DNA Core Submission Number"),0,1) layout.addWidget(QLabel("DNA Core Submission Number"),0,1)
self.core_number = QLineEdit() self.core_number = QLineEdit()

View File

@@ -37,21 +37,21 @@ class SubmissionDetails(QDialog):
# create scrollable interior # create scrollable interior
interior = QScrollArea() interior = QScrollArea()
interior.setParent(self) interior.setParent(self)
self.base_dict = sub.to_dict(full_data=True) # self.base_dict = sub.to_dict(full_data=True)
logger.debug(f"Submission details data:\n{pformat({k:v for k,v in self.base_dict.items() if k != 'samples'})}") # logger.debug(f"Submission details data:\n{pformat({k:v for k,v in self.base_dict.items() if k != 'samples'})}")
# don't want id # # don't want id
del self.base_dict['id'] # del self.base_dict['id']
logger.debug(f"Creating barcode.") # logger.debug(f"Creating barcode.")
if not check_if_app(): # if not check_if_app():
self.base_dict['barcode'] = base64.b64encode(sub.make_plate_barcode(width=120, height=30)).decode('utf-8') # self.base_dict['barcode'] = base64.b64encode(sub.make_plate_barcode(width=120, height=30)).decode('utf-8')
logger.debug(f"Making platemap...") # logger.debug(f"Making platemap...")
self.base_dict['platemap'] = sub.make_plate_map() # self.base_dict['platemap'] = sub.make_plate_map()
self.base_dict, self.template = sub.get_details_template(base_dict=self.base_dict) # self.base_dict, self.template = sub.get_details_template(base_dict=self.base_dict)
self.html = self.template.render(sub=self.base_dict) # self.html = self.template.render(sub=self.base_dict)
self.webview = QWebEngineView(parent=self) self.webview = QWebEngineView(parent=self)
self.webview.setMinimumSize(900, 500) self.webview.setMinimumSize(900, 500)
self.webview.setMaximumSize(900, 500) self.webview.setMaximumSize(900, 500)
self.webview.setHtml(self.html) # self.webview.setHtml(self.html)
self.layout = QVBoxLayout() self.layout = QVBoxLayout()
interior.resize(900, 500) interior.resize(900, 500)
interior.setWidget(self.webview) interior.setWidget(self.webview)
@@ -64,18 +64,46 @@ class SubmissionDetails(QDialog):
# setup channel # setup channel
self.channel = QWebChannel() self.channel = QWebChannel()
self.channel.registerObject('backend', self) self.channel.registerObject('backend', self)
self.submission_details(submission=sub)
self.webview.page().setWebChannel(self.channel) self.webview.page().setWebChannel(self.channel)
@pyqtSlot(str) @pyqtSlot(str)
def sample_details(self, sample): def sample_details(self, sample:str):
# print(f"{string} is in row {row}, column {column}") """
# self.webview.setHtml(f"<html><body><br><br>{sample}</body></html>") Changes details view to summary of Sample
Args:
sample (str): Submitter Id of the sample.
"""
sample = BasicSample.query(submitter_id=sample) sample = BasicSample.query(submitter_id=sample)
base_dict = sample.to_sub_dict(full_data=True) base_dict = sample.to_sub_dict(full_data=True)
base_dict, template = sample.get_details_template(base_dict=base_dict) base_dict, template = sample.get_details_template(base_dict=base_dict)
html = template.render(sample=base_dict) html = template.render(sample=base_dict)
self.webview.setHtml(html) self.webview.setHtml(html)
# sample.show_details(obj=self)
@pyqtSlot(str)
def submission_details(self, submission:str|BasicSubmission):
"""
Sets details view to summary of Submission.
Args:
submission (str | BasicSubmission): Submission of interest.
"""
logger.debug(f"Details for: {submission}")
if isinstance(submission, str):
submission = BasicSubmission.query(rsl_number=submission)
self.base_dict = submission.to_dict(full_data=True)
logger.debug(f"Submission details data:\n{pformat({k:v for k,v in self.base_dict.items() if k != 'samples'})}")
# don't want id
del self.base_dict['id']
logger.debug(f"Creating barcode.")
if not check_if_app():
self.base_dict['barcode'] = base64.b64encode(submission.make_plate_barcode(width=120, height=30)).decode('utf-8')
logger.debug(f"Making platemap...")
self.base_dict['platemap'] = submission.make_plate_map()
self.base_dict, self.template = submission.get_details_template(base_dict=self.base_dict)
self.html = self.template.render(sub=self.base_dict)
self.webview.setHtml(self.html)
def export(self): def export(self):
""" """

View File

@@ -395,7 +395,7 @@ class SubmissionFormWidget(QWidget):
def __init__(self, parent: QWidget, **kwargs) -> None: def __init__(self, parent: QWidget, **kwargs) -> None:
super().__init__(parent) super().__init__(parent)
self.ignore = ['filepath', 'samples', 'reagents', 'csv', 'ctx', 'comment', 'equipment'] self.ignore = ['filepath', 'samples', 'reagents', 'csv', 'ctx', 'comment', 'equipment', 'source_plates']
self.recover = ['filepath', 'samples', 'csv', 'comment', 'equipment'] self.recover = ['filepath', 'samples', 'csv', 'comment', 'equipment']
layout = QVBoxLayout() layout = QVBoxLayout()
for k, v in kwargs.items(): for k, v in kwargs.items():

View File

@@ -46,9 +46,20 @@
{% endfor %}</p> {% endfor %}</p>
{% if sample['submissions'] %}<h2>Submissions:</h2> {% if sample['submissions'] %}<h2>Submissions:</h2>
{% for submission in sample['submissions'] %} {% for submission in sample['submissions'] %}
<p>{{ submission['Plate Name'] }}: {{ submission['Well'] }}</p> <p id="{{ submission['Plate Name'] }}"><b>{{ submission['Plate Name'] }}:</b> {{ submission['Well'] }}</p>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
</body> </body>
<script>
var backend;
new QWebChannel(qt.webChannelTransport, function (channel) {
backend = channel.objects.backend;
});
{% for submission in sample['submissions'] %}
document.getElementById("{{ submission['Plate Name'] }}").addEventListener("dblclick", function(){
backend.submission_details("{{ submission['Plate Name'] }}");
});
{% endfor %}
</script>
</html> </html>