示例#1
0
def advanced_debugging():
    config = get_config()

    st.sidebar.markdown("# Advanced Debugging")
    if st.sidebar.button("Compare Baseline to Output Directory"):
        """
        ## Comparing Results to Baseline
        """

        baseline_directory = pathlib.Path(
            config["debug"]["baseline_directory"]).resolve()

        png_baseline_directory = baseline_directory.joinpath("png")

        baseline_png_paths = [
            path for path in (png_baseline_directory.rglob("*"))
            if path.is_file()
        ]

        relative_png_paths = [
            path.relative_to(png_baseline_directory)
            for path in baseline_png_paths
        ]

        output_dir = pathlib.Path(config["output"]["png_directory"]).resolve()

        evaluation_png_paths = [
            output_dir.joinpath(path) for path in relative_png_paths
        ]

        for baseline, evaluation in zip(baseline_png_paths,
                                        evaluation_png_paths):

            f"### {baseline.parent.name}/{baseline.name}"

            f"`{baseline}`\n\n**vs**\n\n`{evaluation}`"

            baseline_image = imageio.imread(baseline)

            try:
                evaluation_image = imageio.imread(evaluation)
            except FileNotFoundError as e:
                """
                #### File was not found
                """
                st.write(e)
                f"""
                For debugging purposes, here are all the files that
                were found within {str(output_dir)}
                """

                [str(path) for path in output_dir.rglob("*") if path.is_file()]

                return

            agree = np.allclose(baseline_image, evaluation_image)
            f"Images Agree: `{agree}`"
示例#2
0
def main():
    st.write("## Parameters")

    number_of_images = st.number_input("Number of Images", 10)

    width = st.number_input("Width (mm)", 20)
    length = st.number_input("Length (mm)", 24)
    edge_lengths = [width, length]

    # initial_rotation = 0
    bb_diameter = st.number_input("BB Diameter (mm)", 8)
    penumbra = st.number_input("Penumbra (mm)", 2)

    # files = sorted(IMAGES_DIR.glob("*.jpg"), key=lambda t: -os.stat(t).st_mtime)
    # most_recent = files[0:5]

    # most_recent

    files = get_file_list()
    most_recent = sorted(
        files, key=lambda t: -os.stat(t).st_mtime)[0:number_of_images]

    image_path = st.radio("Image to select", options=most_recent)

    plt.imshow(read_image(image_path))
    st.pyplot()

    if st.button("Calculate"):
        img = read_image(image_path)
        x, y, img = iview.iview_image_transform(img)
        field = imginterp.create_interpolated_field(x, y, img)
        initial_centre = findfield.get_centre_of_mass(x, y, img)
        (field_centre,
         field_rotation) = findfield.field_centre_and_rotation_refining(
             field, edge_lengths, penumbra, initial_centre, fixed_rotation=0)

        bb_centre = findbb.optimise_bb_centre(field, bb_diameter, edge_lengths,
                                              penumbra, field_centre,
                                              field_rotation)
        fig = reporting.image_analysis_figure(
            x,
            y,
            img,
            bb_centre,
            field_centre,
            field_rotation,
            bb_diameter,
            edge_lengths,
            penumbra,
        )

        st.write(fig)
        st.pyplot()
示例#3
0
def monaco_patient_directory_picker(patient_id="",
                                    key_namespace="",
                                    advanced_mode_local=False,
                                    site=None):
    monaco_site, monaco_directory = misc.get_site_and_directory(
        "Monaco Plan Location",
        "monaco",
        default=site,
        key=f"{key_namespace}_monaco_site",
    )

    if advanced_mode_local:
        st.write(monaco_directory.resolve())

    patient_id = st.text_input("Patient ID",
                               patient_id,
                               key=f"{key_namespace}_patient_id")
    if advanced_mode_local:
        patient_id

    if patient_id == "":
        st.stop()

    plan_directories = list(monaco_directory.glob(f"*~{patient_id}/plan"))
    if len(plan_directories) == 0:
        if patient_id != "":
            st.write(
                exceptions.NoRecordsFound(
                    f"No Monaco plan directories found for patient ID {patient_id}"
                ))
            st.stop()

        return {"patient_id": patient_id}
    elif len(plan_directories) > 1:
        raise ValueError(
            "More than one patient plan directory found for this ID, "
            "please only have one directory per patient. "
            "Directories found were "
            f"{', '.join([str(path.resolve()) for path in plan_directories])}")

    plan_directory = plan_directories[0]
    patient_directory = pathlib.Path(plan_directory).parent

    return monaco_site, monaco_directory, patient_id, plan_directory, patient_directory
示例#4
0
def display_deliveries(deliveries):
    if not deliveries:
        return 0

    st.write("""
        #### Overview of selected deliveries
        """)

    data = []
    for delivery in deliveries:
        num_control_points = len(delivery.mu)

        if num_control_points != 0:
            total_mu = delivery.mu[-1]
        else:
            total_mu = 0

        data.append([total_mu, num_control_points])

    columns = ["MU", "Number of Data Points"]
    df = pd.DataFrame(data=data, columns=columns)
    st.write(df)

    total_mu = round(df["MU"].sum(), 1)

    st.write(f"Total MU: `{total_mu}`")

    return total_mu
示例#5
0
def convert_png_to_pdf(png_filepath, pdf_filepath):
    st.write("### PDF")
    st.write("Converting PNG to PDF...")

    try:
        subprocess.check_call(
            f'magick convert "{png_filepath}" "{pdf_filepath}"', shell=True)
        success = True
    except subprocess.CalledProcessError:
        try:
            subprocess.check_call(f'convert "{png_filepath}" "{pdf_filepath}"',
                                  shell=True)
            success = True
        except subprocess.CalledProcessError:
            success = False

    if success:
        st.write(f"Created:\n\n`{pdf_filepath}`")

        with open(pdf_filepath, "rb") as f:
            pdf_contents = f.read()

        pdf_filename = pathlib.Path(pdf_filepath).name

        pdf_b64 = base64.b64encode(pdf_contents).decode()
        href = f"""
            <a href="data:file/zip;base64,{pdf_b64}" download='{pdf_filename}'>
                Click to download {pdf_filename}
            </a>
        """
        st.markdown(href, unsafe_allow_html=True)

    else:
        if sys.platform == "win32":
            url_hash_parameter = "#windows"
        else:
            url_hash_parameter = ""

        download_url = (
            f"https://imagemagick.org/script/download.php{url_hash_parameter}")

        st.write(
            _exceptions.UnableToCreatePDF(
                "Please install Image Magick to create PDF reports "
                f"<{download_url}>."))
示例#6
0
文件: _trf.py 项目: lc52520/pymedphys
def _attempt_patient_name_from_mosaiq(headers):
    UNKNOWN_PATIENT_NAME = "Unknown"

    st.write("""
        #### Corresponding Mosaiq SQL Details
        """)

    try:
        (
            machine_centre_map,
            mosaiq_details,
            mosaiq_servers,
        ) = _get_mosaiq_configuration(headers)
    except KeyError:
        st.warning("Need Mosaiq access to determine patient name. "
                   f"Patient name set to '{UNKNOWN_PATIENT_NAME}'.")
        patient_name = UNKNOWN_PATIENT_NAME

        return patient_name

    try:
        mosaiq_details = get_logfile_mosaiq_info(headers, machine_centre_map,
                                                 mosaiq_details,
                                                 mosaiq_servers)
    except _NoMosaiqEntries:
        st.warning(
            "Searched Mosaiq for an entry corresponding to this logfile. "
            "No entry was found. As such, for now, patient name has been "
            f"set to '{UNKNOWN_PATIENT_NAME}'.")
        patient_name = UNKNOWN_PATIENT_NAME

        return patient_name

    mosaiq_details = mosaiq_details.drop("beam_completed", axis=1)
    st.write(mosaiq_details)

    patient_names = set()
    for _, row in mosaiq_details.iterrows():
        st.write(row)
        patient_name = utl_patient.convert_patient_name_from_split(
            row["last_name"], row["first_name"])
        patient_names.add(patient_name)

    patient_name = _utilities.filter_patient_names(patient_names)

    return patient_name
示例#7
0
def run_calculation(
    reference_results,
    evaluation_results,
    gamma_options,
    escan_directory,
    png_output_directory,
):
    st.write("Calculating Reference MU Density...")
    reference_mudensity = calculate_batch_mudensity(
        reference_results["deliveries"])

    st.write("Calculating Evaluation MU Density...")
    evaluation_mudensity = calculate_batch_mudensity(
        evaluation_results["deliveries"])

    st.write("Calculating Gamma...")
    gamma = calculate_gamma(reference_mudensity, evaluation_mudensity,
                            gamma_options)

    patient_id = reference_results["patient_id"]

    st.write("Creating figure...")
    output_base_filename = (
        f"{patient_id} {reference_results['identifier']} vs "
        f"{evaluation_results['identifier']}")
    pdf_filepath = str(
        escan_directory.joinpath(f"{output_base_filename}.pdf").resolve())
    png_record_directory = png_output_directory.joinpath(output_base_filename)
    png_record_directory.mkdir(exist_ok=True)
    png_filepath = str(png_record_directory.joinpath("report.png").resolve())

    try:
        patient_name_text = f"Patient Name: {reference_results['patient_name']}\n"
    except KeyError:
        patient_name_text = ""

    header_text = (f"Patient ID: {patient_id}\n"
                   f"{patient_name_text}"
                   f"Reference: {reference_results['identifier']}\n"
                   f"Evaluation: {evaluation_results['identifier']}\n")

    reference_path_strings = "\n    ".join(
        [str(path.resolve()) for path in reference_results["data_paths"]])
    evaluation_path_strings = "\n    ".join(
        [str(path.resolve()) for path in evaluation_results["data_paths"]])

    footer_text = (f"reference path(s): {reference_path_strings}\n"
                   f"evaluation path(s): {evaluation_path_strings}\n"
                   f"png record: {png_filepath}")

    fig = plot_and_save_results(
        reference_mudensity,
        evaluation_mudensity,
        gamma,
        gamma_options,
        png_record_directory,
        header_text=header_text,
        footer_text=footer_text,
    )

    fig.tight_layout()

    st.write("Saving figure...")
    plt.savefig(png_filepath, dpi=100)
    try:
        subprocess.check_call(
            f'magick convert "{png_filepath}" "{pdf_filepath}"', shell=True)
    except subprocess.CalledProcessError:
        st.write(
            UnableToCreatePDF(
                "Please install Image Magick to create PDF reports "
                "<https://imagemagick.org/script/download.php#windows>."))

    st.write("## Results")
    st.pyplot()
示例#8
0
def monaco_input_method(patient_id="",
                        key_namespace="",
                        advanced_mode_local=False,
                        site=None,
                        **_):
    (
        monaco_site,
        monaco_directory,
        patient_id,
        plan_directory,
        patient_directory,
    ) = st_monaco.monaco_patient_directory_picker(patient_id, key_namespace,
                                                  advanced_mode_local, site)

    patient_name = read_monaco_patient_name(str(patient_directory))

    f"Patient Name: `{patient_name}`"

    all_tel_paths = list(plan_directory.glob("**/*tel.1"))
    all_tel_paths = sorted(all_tel_paths, key=os.path.getmtime)

    plan_names_to_choose_from = [
        str(path.relative_to(plan_directory)) for path in all_tel_paths
    ]

    if len(plan_names_to_choose_from) == 0:
        if patient_id != "":
            st.write(
                st_exceptions.NoRecordsFound(
                    f"No Monaco plans found for patient ID {patient_id}"))
        return {"patient_id": patient_id}
    """
    Select the Monaco plan that correspond to a patient's single fraction.
    If a patient has multiple fraction types (such as a plan with a boost)
    then these fraction types need to be analysed separately.
    """

    selected_monaco_plan = st.radio(
        "Select a Monaco plan",
        plan_names_to_choose_from,
        key=f"{key_namespace}_monaco_plans",
    )

    tel_paths = []

    if selected_monaco_plan is not None:
        current_plans = list(
            monaco_directory.glob(
                f"*~{patient_id}/plan/{selected_monaco_plan}"))
        current_plans = [path.resolve() for path in current_plans]
        if len(current_plans) != 1:
            st.write("Plans found:", current_plans)
            raise ValueError("Exactly one plan should have been found")
        tel_paths += current_plans

    if advanced_mode_local:
        [str(path.resolve()) for path in tel_paths]

    deliveries = cached_deliveries_loading(tel_paths, delivery_from_tel)

    if tel_paths:
        plan_names = ", ".join([path.parent.name for path in tel_paths])
        identifier = f"Monaco ({plan_names})"
    else:
        identifier = None

    if len(deliveries) == 1 and len(deliveries[0].mu) == 0:
        st.write(
            NoControlPointsFound(
                "This is likely due to an as of yet unsupported "
                "Monaco file format. At this point in time 3DCRT "
                "is not yet supported for reading directly from "
                "Monaco. DICOM is though, please export the plan "
                "to RT DICOM and import the data that way."))

    results = {
        "site": monaco_site,
        "patient_id": patient_id,
        "patient_name": patient_name,
        "selected_monaco_plan": selected_monaco_plan,
        "data_paths": tel_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }

    return results
示例#9
0
def icom_input_method(patient_id="",
                      key_namespace="",
                      advanced_mode_local=False,
                      **_):
    icom_directories = _config.get_default_icom_directories()

    if advanced_mode_local:
        st.write("iCOM patient directories", icom_directories)

    icom_directories = [pathlib.Path(path) for path in icom_directories]

    if advanced_mode_local:
        patient_id = st.text_input("Patient ID",
                                   patient_id,
                                   key=f"{key_namespace}_patient_id")
        st.write(patient_id)

    icom_deliveries = []
    for path in icom_directories:
        icom_deliveries += list(path.glob(f"{patient_id}_*/*.xz"))

    icom_deliveries = sorted(icom_deliveries)

    icom_files_to_choose_from = [path.stem for path in icom_deliveries]

    timestamps = list(
        pd.to_datetime(icom_files_to_choose_from,
                       format="%Y%m%d_%H%M%S").astype(str))

    choice_path_map = dict(zip(timestamps, icom_deliveries))

    st.write("""
        Here you need to select the timestamps that correspond to a single
        fraction of the plan selected above. Most of the time
        you will only need to select one timestamp here, however in some
        cases you may need to select multiple timestamps.

        This can occur if for example a single fraction was delivered in separate
        beams due to either a beam interrupt, or the fraction being spread
        over multiple energies
        """)

    if len(timestamps) == 0:
        if patient_id != "":
            st.write(
                _exceptions.NoRecordsFound(
                    f"No iCOM delivery record found for patient ID {patient_id}"
                ))
        return {"patient_id": patient_id}

    if len(timestamps) == 1:
        default_timestamp = [timestamps[0]]
    else:
        default_timestamp = []

    timestamps = sorted(timestamps, reverse=True)

    try:
        selected_icom_deliveries = st.multiselect(
            "Select iCOM delivery timestamp(s)",
            timestamps,
            default=default_timestamp,
            key=f"{key_namespace}_icom_deliveries",
        )
    except st.errors.StreamlitAPIException:
        st.write(f"Default timestamp = `{default_timestamp}`")
        st.write(f"All timestamps = `{timestamps}`")
        raise

    icom_filenames = [
        path.replace(" ", "_").replace("-", "").replace(":", "")
        for path in selected_icom_deliveries
    ]

    icom_paths = []
    for selected in selected_icom_deliveries:
        icom_paths.append(choice_path_map[selected])

    if advanced_mode_local:
        st.write([str(path.resolve()) for path in icom_paths])

    patient_names = set()
    for icom_path in icom_paths:
        patient_name = str(icom_path.parent.name).split("_")[-1]
        try:
            patient_name = utl_patient.convert_patient_name_from_split(
                *patient_name.split(", "))
        except:  # pylint: disable = bare-except
            pass

        patient_names.add(patient_name)

    patient_name = _utilities.filter_patient_names(patient_names)

    icom_streams = load_icom_streams(icom_paths)
    deliveries = _deliveries.cached_deliveries_loading(
        icom_streams, _deliveries.delivery_from_icom)

    if selected_icom_deliveries:
        identifier = f"iCOM ({icom_filenames[0]})"
    else:
        identifier = None

    if len(deliveries) == 0:
        st.write(
            _exceptions.InputRequired(
                "Please select at least one iCOM delivery"))
        st.stop()

    results = {
        "site": None,
        "patient_id": patient_id,
        "patient_name": patient_name,
        "selected_icom_deliveries": selected_icom_deliveries,
        "data_paths": icom_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }

    return results
示例#10
0
def trf_input_method(patient_id="", key_namespace="", **_):
    indexed_trf_directory = get_indexed_trf_directory()

    patient_id = st.text_input("Patient ID",
                               patient_id,
                               key=f"{key_namespace}_patient_id")
    patient_id

    filepaths = list(
        indexed_trf_directory.glob(f"*/{patient_id}_*/*/*/*/*.trf"))

    raw_timestamps = [
        "_".join(path.parent.name.split("_")[0:2]) for path in filepaths
    ]
    timestamps = list(
        pd.to_datetime(raw_timestamps, format="%Y-%m-%d_%H%M%S").astype(str))

    timestamp_filepath_map = dict(zip(timestamps, filepaths))

    timestamps = sorted(timestamps, reverse=True)

    if len(timestamps) == 0:
        if patient_id != "":
            st.write(
                NoRecordsFound(
                    f"No TRF log file found for patient ID {patient_id}"))
        return {"patient_id": patient_id}

    if len(timestamps) == 1:
        default_timestamp = timestamps[0]
    else:
        default_timestamp = []

    selected_trf_deliveries = st.multiselect(
        "Select TRF delivery timestamp(s)",
        timestamps,
        default=default_timestamp,
        key=f"{key_namespace}_trf_deliveries",
    )

    if not selected_trf_deliveries:
        return {}
    """
    #### TRF filepath(s)
    """

    selected_filepaths = [
        timestamp_filepath_map[timestamp]
        for timestamp in selected_trf_deliveries
    ]
    [str(path.resolve()) for path in selected_filepaths]
    """
    #### Log file header(s)
    """

    headers = []
    tables = []
    for path in selected_filepaths:
        header, table = read_trf(path)
        headers.append(header)
        tables.append(table)

    headers = pd.concat(headers)
    headers.reset_index(inplace=True)
    headers.drop("index", axis=1, inplace=True)

    headers
    """
    #### Corresponding Mosaiq SQL Details
    """

    mosaiq_details = get_logfile_mosaiq_info(headers)
    mosaiq_details = mosaiq_details.drop("beam_completed", axis=1)

    mosaiq_details

    patient_names = set()
    for _, row in mosaiq_details.iterrows():
        row
        patient_name = utl_patient.convert_patient_name_from_split(
            row["last_name"], row["first_name"])
        patient_names.add(patient_name)

    patient_name = filter_patient_names(patient_names)

    deliveries = cached_deliveries_loading(tables, delivery_from_trf)

    individual_identifiers = [
        f"{path.parent.parent.parent.parent.name} {path.parent.name}"
        for path in selected_filepaths
    ]

    identifier = f"TRF ({individual_identifiers[0]})"

    return {
        "patient_id": patient_id,
        "patient_name": patient_name,
        "data_paths": selected_filepaths,
        "identifier": identifier,
        "deliveries": deliveries,
    }
示例#11
0
def dicom_input_method(  # pylint: disable = too-many-return-statements
        key_namespace="",
        patient_id="",
        **_):
    FILE_UPLOAD = "File upload"
    MONACO_SEARCH = "Search Monaco file export location"

    dicom_export_locations = get_dicom_export_locations()

    import_method = st.radio(
        "DICOM import method",
        [FILE_UPLOAD, MONACO_SEARCH],
        key=f"{key_namespace}_dicom_file_import_method",
    )

    if import_method == FILE_UPLOAD:
        dicom_plan_bytes = st.file_uploader(
            "Upload DICOM RT Plan File",
            key=f"{key_namespace}_dicom_plan_uploader")

        if dicom_plan_bytes is None:
            return {}

        try:
            dicom_plan = pydicom.read_file(dicom_plan_bytes, force=True)
        except:  # pylint: disable = bare-except
            st.write(WrongFileType("Does not appear to be a DICOM file"))
            return {}

        if dicom_plan.SOPClassUID != DICOM_PLAN_UID:
            st.write(
                WrongFileType(
                    "The DICOM type needs to be an RT DICOM Plan file"))
            return {}

        data_paths = ["Uploaded DICOM file"]

    if import_method == MONACO_SEARCH:
        site_options = list(dicom_export_locations.keys())
        monaco_site = st.radio("Monaco Export Location",
                               site_options,
                               key=f"{key_namespace}_monaco_site")
        monaco_export_directory = dicom_export_locations[monaco_site]
        st.write(monaco_export_directory.resolve())

        patient_id = st.text_input("Patient ID",
                                   patient_id,
                                   key=f"{key_namespace}_patient_id")

        found_dicom_files = list(
            monaco_export_directory.glob(f"{patient_id}_*.dcm"))

        dicom_plans = {}

        for path in found_dicom_files:
            dcm = load_dicom_file_if_plan(path)
            if dcm is not None:
                dicom_plans[path.name] = dcm

        dicom_plan_options = list(dicom_plans.keys())

        if len(dicom_plan_options) == 0 and patient_id != "":
            st.write(
                NoRecordsFound(
                    f"No exported DICOM RT plans found for Patient ID {patient_id} "
                    f"within the directory {monaco_export_directory}"))
            return {"patient_id": patient_id}

        if len(dicom_plan_options) == 1:
            selected_plan = dicom_plan_options[0]
        else:
            selected_plan = st.radio(
                "Select DICOM Plan",
                dicom_plan_options,
                key=f"{key_namespace}_select_monaco_export_plan",
            )

        f"DICOM file being used: `{selected_plan}`"

        dicom_plan = dicom_plans[selected_plan]
        data_paths = [monaco_export_directory.joinpath(selected_plan)]

    patient_id = str(dicom_plan.PatientID)
    f"Patient ID: `{patient_id}`"

    patient_name = str(dicom_plan.PatientName)
    patient_name = utl_patient.convert_patient_name(patient_name)

    f"Patient Name: `{patient_name}`"

    rt_plan_name = str(dicom_plan.RTPlanName)
    f"Plan Name: `{rt_plan_name}`"

    try:
        deliveries_all_fractions = pymedphys.Delivery.from_dicom(
            dicom_plan, fraction_number="all")
    except AttributeError:
        st.write(WrongFileType("Does not appear to be a photon DICOM plan"))
        return {}

    fractions = list(deliveries_all_fractions.keys())
    if len(fractions) == 1:
        delivery = deliveries_all_fractions[fractions[0]]
    else:
        fraction_choices = {}

        for fraction, delivery in deliveries_all_fractions.items():
            rounded_mu = round(delivery.mu[-1], 1)

            fraction_choices[
                f"Perscription {fraction} with {rounded_mu} MU"] = fraction

        fraction_selection = st.radio(
            "Select relevant perscription",
            list(fraction_choices.keys()),
            key=f"{key_namespace}_dicom_perscription_chooser",
        )

        fraction_number = fraction_choices[fraction_selection]
        delivery = deliveries_all_fractions[fraction_number]

    deliveries = [delivery]

    identifier = f"DICOM ({rt_plan_name})"

    return {
        "patient_id": patient_id,
        "patient_name": patient_name,
        "data_paths": data_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }
示例#12
0
def main():
    st.write("""
        # Electron Insert Factors
        """)

    patient_id = st.text_input("Patient ID")

    if patient_id == "":
        st.stop()

    rccc_string_search_pattern = r"\\monacoda\FocalData\RCCC\1~Clinical\*~{}\plan\*\*tel.1".format(
        patient_id)
    rccc_filepath_list = glob(rccc_string_search_pattern)

    nbccc_string_search_pattern = r"\\tunnel-nbcc-monaco\FOCALDATA\NBCCC\1~Clinical\*~{}\plan\*\*tel.1".format(
        patient_id)
    nbccc_filepath_list = glob(nbccc_string_search_pattern)

    sash_string_search_pattern = r"\\tunnel-sash-monaco\Users\Public\Documents\CMS\FocalData\SASH\1~Clinical\*~{}\plan\*\*tel.1".format(
        patient_id)
    sash_filepath_list = glob(sash_string_search_pattern)

    filepath_list = np.concatenate(
        [rccc_filepath_list, nbccc_filepath_list, sash_filepath_list])

    electronmodel_regex = r"RiverinaAgility - (\d+)MeV"
    applicator_regex = r"(\d+)X\d+"

    insert_data = dict()  # type: ignore

    for telfilepath in filepath_list:
        insert_data[telfilepath] = dict()

        with open(telfilepath, "r") as file:
            telfilecontents = np.array(file.read().splitlines())

        insert_data[telfilepath]["reference_index"] = []
        for i, item in enumerate(telfilecontents):
            if re.search(electronmodel_regex, item):
                insert_data[telfilepath]["reference_index"] += [i]

        insert_data[telfilepath]["applicators"] = [
            re.search(applicator_regex,
                      telfilecontents[i + 12]).group(1)  # type: ignore
            for i in insert_data[telfilepath]["reference_index"]
        ]

        insert_data[telfilepath]["energies"] = [
            re.search(electronmodel_regex,
                      telfilecontents[i]).group(1)  # type: ignore
            for i in insert_data[telfilepath]["reference_index"]
        ]

    for telfilepath in filepath_list:
        with open(telfilepath, "r") as file:
            telfilecontents = np.array(file.read().splitlines())

        insert_data[telfilepath]["x"] = []
        insert_data[telfilepath]["y"] = []

        for i, index in enumerate(insert_data[telfilepath]["reference_index"]):
            insert_initial_range = telfilecontents[
                index +
                51::]  # coords start 51 lines after electron model name
            insert_stop = np.where(insert_initial_range == "0")[0][
                0]  # coords stop right before a line containing 0

            insert_coords_string = insert_initial_range[:insert_stop]
            insert_coords = np.fromstring(",".join(insert_coords_string),
                                          sep=",")
            insert_data[telfilepath]["x"].append(insert_coords[0::2] / 10)
            insert_data[telfilepath]["y"].append(insert_coords[1::2] / 10)

    for telfilepath in filepath_list:
        insert_data[telfilepath]["width"] = []
        insert_data[telfilepath]["length"] = []
        insert_data[telfilepath]["circle_centre"] = []
        insert_data[telfilepath]["P/A"] = []

        for i in range(len(insert_data[telfilepath]["reference_index"])):

            width, length, circle_centre = electronfactors.parameterise_insert(
                insert_data[telfilepath]["x"][i],
                insert_data[telfilepath]["y"][i])

            insert_data[telfilepath]["width"].append(width)
            insert_data[telfilepath]["length"].append(length)
            insert_data[telfilepath]["circle_centre"].append(circle_centre)

            insert_data[telfilepath]["P/A"].append(
                electronfactors.convert2_ratio_perim_area(width, length))

    data_filename = r"S:\Physics\RCCC Specific Files\Dosimetry\Elekta_EFacs\electron_factor_measured_data.csv"
    data = pd.read_csv(data_filename)

    width_data = data["Width (cm @ 100SSD)"]
    length_data = data["Length (cm @ 100SSD)"]
    factor_data = data["RCCC Inverse factor (dose open / dose cutout)"]

    p_on_a_data = electronfactors.convert2_ratio_perim_area(
        width_data, length_data)

    for telfilepath in filepath_list:
        insert_data[telfilepath]["model_factor"] = []

        for i in range(len(insert_data[telfilepath]["reference_index"])):
            applicator = float(insert_data[telfilepath]["applicators"][i])
            energy = float(insert_data[telfilepath]["energies"][i])
            ssd = 100

            reference = ((data["Energy (MeV)"] == energy)
                         & (data["Applicator (cm)"] == applicator)
                         & (data["SSD (cm)"] == ssd))

            number_of_measurements = np.sum(reference)

            if number_of_measurements < 8:
                insert_data[telfilepath]["model_factor"].append(np.nan)
            else:
                insert_data[telfilepath]["model_factor"].append(
                    electronfactors.spline_model_with_deformability(
                        insert_data[telfilepath]["width"],
                        insert_data[telfilepath]["P/A"],
                        width_data[reference],
                        p_on_a_data[reference],
                        factor_data[reference],
                    )[0])

    for telfilepath in filepath_list:
        st.write("---")
        st.write("Filepath: `{}`".format(telfilepath))

        for i in range(len(insert_data[telfilepath]["reference_index"])):
            applicator = float(insert_data[telfilepath]["applicators"][i])
            energy = float(insert_data[telfilepath]["energies"][i])
            ssd = 100

            st.write("Applicator: `{} cm` | Energy: `{} MeV`".format(
                applicator, energy))

            width = insert_data[telfilepath]["width"][i]
            length = insert_data[telfilepath]["length"][i]

            plt.figure()
            plot_insert(
                insert_data[telfilepath]["x"][i],
                insert_data[telfilepath]["y"][i],
                insert_data[telfilepath]["width"][i],
                insert_data[telfilepath]["length"][i],
                insert_data[telfilepath]["circle_centre"][i],
            )

            reference = ((data["Energy (MeV)"] == energy)
                         & (data["Applicator (cm)"] == applicator)
                         & (data["SSD (cm)"] == ssd))

            number_of_measurements = np.sum(reference)

            plt.figure()
            if number_of_measurements < 8:
                plt.scatter(
                    width_data[reference],
                    length_data[reference],
                    s=100,
                    c=factor_data[reference],
                    cmap="viridis",
                    zorder=2,
                )
                plt.colorbar()
            else:
                plot_model(
                    width_data[reference],
                    length_data[reference],
                    factor_data[reference],
                )

            reference_data_table = pd.concat(
                [
                    width_data[reference], length_data[reference],
                    factor_data[reference]
                ],
                axis=1,
            )
            reference_data_table.sort_values(
                ["RCCC Inverse factor (dose open / dose cutout)"],
                ascending=False,
                inplace=True,
            )

            st.write(reference_data_table)

            st.pyplot()

            factor = insert_data[telfilepath]["model_factor"][i]

            st.write(
                "Width: `{0:0.2f} cm` | Length: `{1:0.2f} cm` | Factor: `{2:0.3f}`"
                .format(width, length, factor))
示例#13
0
def main():
    st.write("""
        # MU Density comparison tool

        Tool to compare the MU Density between planned and delivery.
        """)

    config = st_config.get_config()

    st.sidebar.markdown("""
        # MU Density Overview
        """)

    st.sidebar.markdown("""
        ## Reference
        """)

    set_reference_overview = sidebar_overview()

    st.sidebar.markdown("""
        ## Evaluation
        """)

    set_evaluation_overview = sidebar_overview()

    overview_updater_map = {
        "reference": set_reference_overview,
        "evaluation": set_evaluation_overview,
    }

    st.sidebar.markdown("""
        # Status indicators
        """)

    show_status_indicators()

    st.sidebar.markdown("""
        # Advanced options

        Enable advanced functionality by ticking the below.
        """)
    advanced_mode = st.sidebar.checkbox("Run in Advanced Mode")

    gamma_options = _config.get_gamma_options(advanced_mode)

    data_option_functions = {
        "monaco": _monaco.monaco_input_method,
        "dicom": _dicom.dicom_input_method,
        "icom": _icom.icom_input_method,
        "trf": _trf.trf_input_method,
        "mosaiq": _mosaiq.mosaiq_input_method,
    }

    default_reference_id = config["data_methods"]["default_reference"]
    default_evaluation_id = config["data_methods"]["default_evaluation"]
    available_data_methods = config["data_methods"]["available"]

    default_reference = DATA_OPTION_LABELS[default_reference_id]
    default_evaluation = DATA_OPTION_LABELS[default_evaluation_id]

    data_method_map = {}
    for method in available_data_methods:
        data_method_map[
            DATA_OPTION_LABELS[method]] = data_option_functions[method]

    st.write("""
        ## Selection of data to compare
        """)

    st.write("""
        ### Reference
        """)

    reference_results = get_input_data_ui(
        overview_updater_map,
        data_method_map,
        default_reference,
        "reference",
        advanced_mode,
    )

    st.write("""
        ### Evaluation
        """)

    evaluation_results = get_input_data_ui(
        overview_updater_map,
        data_method_map,
        default_evaluation,
        "evaluation",
        advanced_mode,
        **reference_results,
    )

    st.write("""
        ## Output Locations
        """)

    st.write("""
        ### eSCAN Directory

        The location to save the produced pdf report.
        """)

    default_site = evaluation_results.get("site", None)
    if default_site is None:
        default_site = reference_results.get("site", None)

    _, escan_directory = st_misc.get_site_and_directory(
        "eScan Site",
        "escan",
        default=default_site,
        key="escan_export_site_picker")

    escan_directory = pathlib.Path(
        os.path.expanduser(escan_directory)).resolve()

    if advanced_mode:
        st.write(escan_directory)

    default_png_output_directory = config["output"]["png_directory"]

    if advanced_mode:
        st.write("""
            ### Image record

            Path to save the image of the results for posterity
            """)

        png_output_directory = pathlib.Path(
            st.text_input("png output directory",
                          default_png_output_directory))
        st.write(png_output_directory.resolve())

    else:
        png_output_directory = pathlib.Path(default_png_output_directory)

    png_output_directory = pathlib.Path(
        os.path.expanduser(png_output_directory)).resolve()

    st.write("""
        ## Calculation
        """)

    if st.button("Run Calculation"):

        st.write("""
            ### MU Density usage warning
            """)

        st.warning(pymedphys.mudensity.WARNING_MESSAGE)

        st.write("""
            ### Calculation status
            """)

        run_calculation(
            reference_results,
            evaluation_results,
            gamma_options,
            escan_directory,
            png_output_directory,
        )

    if advanced_mode:
        advanced_debugging()
示例#14
0
def run_calculation(
    reference_results,
    evaluation_results,
    gamma_options,
    escan_directory,
    png_output_directory,
):
    st.write("Calculating Reference MU Density...")
    reference_mudensity = calculate_batch_mudensity(
        reference_results["deliveries"])

    st.write("Calculating Evaluation MU Density...")
    evaluation_mudensity = calculate_batch_mudensity(
        evaluation_results["deliveries"])

    st.write("Calculating Gamma...")
    gamma = calculate_gamma(reference_mudensity, evaluation_mudensity,
                            gamma_options)

    patient_id = reference_results["patient_id"]

    st.write("Creating figure...")
    output_base_filename = (
        f"{patient_id} {reference_results['identifier']} vs "
        f"{evaluation_results['identifier']}")
    pdf_filepath = str(
        escan_directory.joinpath(f"{output_base_filename}.pdf").resolve())
    png_record_directory = png_output_directory.joinpath(output_base_filename)
    png_record_directory.mkdir(exist_ok=True)
    png_filepath = str(png_record_directory.joinpath("report.png").resolve())

    try:
        patient_name_text = f"Patient Name: {reference_results['patient_name']}\n"
    except KeyError:
        patient_name_text = ""

    header_text = (f"Patient ID: {patient_id}\n"
                   f"{patient_name_text}"
                   f"Reference: {reference_results['identifier']}\n"
                   f"Evaluation: {evaluation_results['identifier']}\n")

    reference_path_strings = "\n    ".join(
        [str(path.resolve()) for path in reference_results["data_paths"]])
    evaluation_path_strings = "\n    ".join(
        [str(path.resolve()) for path in evaluation_results["data_paths"]])

    footer_text = (f"reference path(s): {reference_path_strings}\n"
                   f"evaluation path(s): {evaluation_path_strings}\n"
                   f"png record: {png_filepath}")

    fig = plot_and_save_results(
        reference_mudensity,
        evaluation_mudensity,
        gamma,
        gamma_options,
        png_record_directory,
        header_text=header_text,
        footer_text=footer_text,
    )

    fig.tight_layout()

    st.write("## Results")
    st.pyplot(fig)

    st.write("## Saving reports")
    st.write("### PNG")
    st.write("Saving figure as PNG...")
    plt.savefig(png_filepath, dpi=100)
    st.write(f"Saved:\n\n`{png_filepath}`")
    convert_png_to_pdf(png_filepath, pdf_filepath)
示例#15
0
def main():
    centres = ["rccc", "nbcc", "sash"]
    servers = {
        "rccc": "msqsql",
        "nbcc": "physics-server:31433",
        "sash": "physics-server",
    }
    physics_locations = {
        "rccc": "Physics_Check",
        "nbcc": "Physics",
        "sash": "Physics_Check",
    }

    cursors = {
        centre: st_mosaiq.get_mosaiq_cursor_in_bucket(servers[centre])
        for centre in centres
    }

    st.write("# Mosaiq QCLs")

    if st.button("Refresh"):
        st.experimental_rerun()

    for centre in centres:
        st.write(f"## {centre.upper()}")

        cursor_bucket = cursors[centre]
        physics_location = physics_locations[centre]

        try:
            table = msq_helpers.get_incomplete_qcls(cursor_bucket["cursor"],
                                                    physics_location)
        except (pymssql.InterfaceError, pymssql.OperationalError) as e:
            st.write(e)
            cursor_bucket["cursor"] = st_mosaiq.uncached_get_mosaiq_cursor(
                servers[centre])
            table = msq_helpers.get_incomplete_qcls(cursor_bucket["cursor"],
                                                    physics_location)

        table_dict = collections.OrderedDict()

        for index, row in table.iterrows():
            patient_name = f"{str(row.last_name).upper()}, {str(row.first_name).lower().capitalize()}"

            table_dict[index] = collections.OrderedDict({
                "Due":
                row.due.strftime("%Y-%m-%d"),
                "Patient":
                f"{row.patient_id} {patient_name}",
                "Instructions":
                row.instructions,
                "Comment":
                row.comment,
                "Task":
                row.task,
            })

        formated_table = pd.DataFrame.from_dict(table_dict).T
        formated_table = formated_table.reindex(
            ["Due", "Patient", "Instructions", "Comment", "Task"], axis=1)

        st.write(formated_table)
示例#16
0
def main():
    config = get_config()

    st.sidebar.markdown("""
        # Overview
        """)

    st.sidebar.markdown("""
        ## Reference
        """)

    set_reference_overview = sidebar_overview()

    st.sidebar.markdown("""
        ## Evaluation
        """)

    set_evaluation_overview = sidebar_overview()

    overview_updater_map = {
        "reference": set_reference_overview,
        "evaluation": set_evaluation_overview,
    }

    st.sidebar.markdown("""
        # Status indicators
        """)

    show_status_indicators()

    st.sidebar.markdown("""
        # Advanced options

        Enable advanced functionality by ticking the below.
        """)
    advanced_mode = st.sidebar.checkbox("Run in Advanced Mode")

    gamma_options = get_gamma_options(advanced_mode)

    data_option_functions = {
        "monaco": monaco_input_method,
        "dicom": dicom_input_method,
        "icom": icom_input_method,
        "trf": trf_input_method,
        "mosaiq": mosaiq_input_method,
    }

    default_reference_id = config["data_methods"]["default_reference"]
    default_evaluation_id = config["data_methods"]["default_evaluation"]
    available_data_methods = config["data_methods"]["available"]

    default_reference = DATA_OPTION_LABELS[default_reference_id]
    default_evaluation = DATA_OPTION_LABELS[default_evaluation_id]

    data_method_map = {}
    for method in available_data_methods:
        data_method_map[
            DATA_OPTION_LABELS[method]] = data_option_functions[method]
    """
    ### Reference
    """

    reference_results = get_input_data_ui(
        overview_updater_map,
        data_method_map,
        default_reference,
        "reference",
        advanced_mode,
    )
    """
    ### Evaluation
    """

    evaluation_results = get_input_data_ui(
        overview_updater_map,
        data_method_map,
        default_evaluation,
        "evaluation",
        advanced_mode,
        **reference_results,
    )
    """
    ## Output Locations
    """
    """
    ### eSCAN Directory

    The location to save the produced pdf report.
    """

    site_directories = get_site_directories()

    site_options = list(site_directories.keys())
    escan_site = st.radio("eScan Site", site_options)
    escan_directory = site_directories[escan_site]["escan"]

    if advanced_mode:
        st.write(escan_directory.resolve())

    default_png_output_directory = config["output"]["png_directory"]

    if advanced_mode:
        """
        ### Image record

        Path to save the image of the results for posterity
        """

        png_output_directory = pathlib.Path(
            st.text_input("png output directory",
                          default_png_output_directory))
        st.write(png_output_directory.resolve())

    else:
        png_output_directory = pathlib.Path(default_png_output_directory)
    """
    ## Calculation
    """

    if st.button("Run Calculation"):
        run_calculation(
            reference_results,
            evaluation_results,
            gamma_options,
            escan_directory,
            png_output_directory,
        )

    if advanced_mode:
        advanced_debugging()
示例#17
0
def monaco_input_method(patient_id="",
                        key_namespace="",
                        advanced_mode_local=False,
                        **_):

    site_directories = get_site_directories()

    site_options = list(site_directories.keys())
    monaco_site = st.radio("Monaco Plan Location",
                           site_options,
                           key=f"{key_namespace}_monaco_site")
    monaco_directory = site_directories[monaco_site]["monaco"]

    if advanced_mode_local:
        st.write(monaco_directory.resolve())

    patient_id = st.text_input("Patient ID",
                               patient_id,
                               key=f"{key_namespace}_patient_id")
    if advanced_mode_local:
        patient_id
    elif patient_id == "":
        raise st.ScriptRunner.StopException()

    patient_directories = monaco_directory.glob(f"*~{patient_id}")

    patient_names = set()
    for patient_directory in patient_directories:
        patient_names.add(read_monaco_patient_name(str(patient_directory)))

    patient_name = filter_patient_names(patient_names)

    f"Patient Name: `{patient_name}`"

    plan_directories = list(monaco_directory.glob(f"*~{patient_id}/plan"))
    if len(plan_directories) == 0:
        if patient_id != "":
            st.write(
                NoRecordsFound(
                    f"No Monaco plan directories found for patient ID {patient_id}"
                ))
        return {"patient_id": patient_id}
    elif len(plan_directories) > 1:
        raise ValueError(
            "More than one patient plan directory found for this ID, "
            "please only have one directory per patient. "
            "Directories found were "
            f"{', '.join([str(path.resolve()) for path in plan_directories])}")

    plan_directory = plan_directories[0]

    all_tel_paths = list(plan_directory.glob("**/*tel.1"))
    all_tel_paths = sorted(all_tel_paths, key=os.path.getmtime)

    plan_names_to_choose_from = [
        str(path.relative_to(plan_directory)) for path in all_tel_paths
    ]

    if len(plan_names_to_choose_from) == 0:
        if patient_id != "":
            st.write(
                NoRecordsFound(
                    f"No Monaco plans found for patient ID {patient_id}"))
        return {"patient_id": patient_id}
    """
    Select the Monaco plan that correspond to a patient's single fraction.
    If a patient has multiple fraction types (such as a plan with a boost)
    then these fraction types need to be analysed separately.
    """

    selected_monaco_plan = st.radio(
        "Select a Monaco plan",
        plan_names_to_choose_from,
        key=f"{key_namespace}_monaco_plans",
    )

    tel_paths = []

    if selected_monaco_plan is not None:
        current_plans = list(
            monaco_directory.glob(
                f"*~{patient_id}/plan/{selected_monaco_plan}"))
        current_plans = [path.resolve() for path in current_plans]
        if len(current_plans) != 1:
            st.write("Plans found:", current_plans)
            raise ValueError("Exactly one plan should have been found")
        tel_paths += current_plans

    if advanced_mode_local:
        [str(path.resolve()) for path in tel_paths]

    deliveries = cached_deliveries_loading(tel_paths, delivery_from_tel)

    if tel_paths:
        plan_names = ", ".join([path.parent.name for path in tel_paths])
        identifier = f"Monaco ({plan_names})"
    else:
        identifier = None

    if len(deliveries) == 1 and len(deliveries[0].mu) == 0:
        st.write(
            NoControlPointsFound(
                "This is likely due to an as of yet unsupported "
                "Monaco file format. At this point in time 3DCRT "
                "is not yet supported for reading directly from "
                "Monaco. DICOM is though, please export the plan "
                "to RT DICOM and import the data that way."))

    results = {
        "patient_id": patient_id,
        "patient_name": patient_name,
        "selected_monaco_plan": selected_monaco_plan,
        "data_paths": tel_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }

    return results
示例#18
0
def main():
    st.write("# Anonymise Monaco Files")

    st.write("## Select Patient")

    (
        monaco_site,
        _,
        patient_id,
        _,
        patient_directory,
    ) = st_monaco.monaco_patient_directory_picker(advanced_mode_local=True)

    st.write(f"Directory to anonymise: `{patient_directory}`")

    st.write("## Select Export Location")

    _, export_directory = st_misc.get_site_and_directory(
        "Site to save anonymised zip file",
        "anonymised_monaco",
        default=monaco_site,
        key="export_site",
    )

    st.write(f"Export directory: `{export_directory}`")

    zip_path = pathlib.Path(export_directory).joinpath(f"{patient_id}.zip")

    st.write(f"Zip file to be created: `{zip_path}`")

    if zip_path.exists():
        st.write(FileExistsError("This zip file already exists."))
        if st.button("Delete zip file"):
            zip_path.unlink()
            st_rerun.rerun()

        st.stop()

    if st.button("Copy and Anonymise"):
        with tempfile.TemporaryDirectory() as temp_dir:
            pl_temp_dir = pathlib.Path(temp_dir)
            new_temp_location = pl_temp_dir.joinpath(patient_directory.name)

            st.write("Copying to temp directory, skipping DICOM files...")

            shutil.copytree(
                patient_directory,
                new_temp_location,
                ignore=shutil.ignore_patterns("*.DCM", "demographic.*"),
            )

            st.write("Creating anonymised demographic file...")

            new_demographic_file = new_temp_location.joinpath(
                f"demographic.{patient_id}"
            )

            shutil.copy2(ANON_DEMOGRAPHIC_FILE, new_demographic_file)
            with open(new_demographic_file, "r") as f:
                demographic_data = f.readlines()

            demographic_data[3] = demographic_data[3].replace("000000", patient_id)

            with open(new_demographic_file, "w") as f:
                f.writelines(demographic_data)

            st.write("Creating zip file...")

            shutil.make_archive(
                str(zip_path.with_suffix("")),
                "zip",
                root_dir=str(pl_temp_dir.resolve()),
                base_dir=f"{patient_directory.name}",
            )

            st.write("Complete!")
示例#19
0
def icom_input_method(patient_id="",
                      icom_directory=None,
                      key_namespace="",
                      advanced_mode_local=False,
                      **_):
    if icom_directory is None:
        icom_directory = get_default_icom_directory()

    if advanced_mode_local:
        icom_directory = st.text_input(
            "iCOM Patient Directory",
            str(icom_directory),
            key=f"{key_namespace}_icom_directory",
        )

    icom_directory = pathlib.Path(icom_directory)

    if advanced_mode_local:
        patient_id = st.text_input("Patient ID",
                                   patient_id,
                                   key=f"{key_namespace}_patient_id")
        patient_id

    icom_deliveries = list(icom_directory.glob(f"{patient_id}_*/*.xz"))
    icom_deliveries = sorted(icom_deliveries)

    icom_files_to_choose_from = [path.stem for path in icom_deliveries]

    timestamps = list(
        pd.to_datetime(icom_files_to_choose_from,
                       format="%Y%m%d_%H%M%S").astype(str))
    """
    Here you need to select the timestamps that correspond to a single
    fraction of the plan selected above. Most of the time
    you will only need to select one timestamp here, however in some
    cases you may need to select multiple timestamps.

    This can occur if for example a single fraction was delivered in separate
    beams due to either a beam interupt, or the fraction being spread
    over multiple energies
    """

    if len(timestamps) == 0:
        if patient_id != "":
            st.write(
                NoRecordsFound(
                    f"No iCOM delivery record found for patient ID {patient_id}"
                ))
        return {"patient_id": patient_id}

    if len(timestamps) == 1:
        default_timestamp = timestamps[0]
    else:
        default_timestamp = []

    timestamps = sorted(timestamps, reverse=True)

    selected_icom_deliveries = st.multiselect(
        "Select iCOM delivery timestamp(s)",
        timestamps,
        default=default_timestamp,
        key=f"{key_namespace}_icom_deliveries",
    )

    icom_filenames = [
        path.replace(" ", "_").replace("-", "").replace(":", "")
        for path in selected_icom_deliveries
    ]

    icom_paths = []
    for icom_filename in icom_filenames:
        icom_paths += list(
            icom_directory.glob(f"{patient_id}_*/{icom_filename}.xz"))

    if advanced_mode_local:
        [str(path.resolve()) for path in icom_paths]

    patient_names = set()
    for icom_path in icom_paths:
        patient_name = str(icom_path.parent.name).split("_")[-1]
        try:
            patient_name = utl_patient.convert_patient_name_from_split(
                *patient_name.split(", "))
        except:  # pylint: disable = bare-except
            pass

        patient_names.add(patient_name)

    patient_name = filter_patient_names(patient_names)

    icom_streams = load_icom_streams(icom_paths)
    deliveries = cached_deliveries_loading(icom_streams, delivery_from_icom)

    if selected_icom_deliveries:
        identifier = f"iCOM ({icom_filenames[0]})"
    else:
        identifier = None

    if len(deliveries) == 0:
        st.write(InputRequired("Please select at least one iCOM delivery"))

    results = {
        "patient_id": patient_id,
        "patient_name": patient_name,
        "icom_directory": str(icom_directory),
        "selected_icom_deliveries": selected_icom_deliveries,
        "data_paths": icom_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }

    return results
示例#20
0
def pseudonymise_buffer_list(file_buffer_list: list):
    """Pseudonymises the contents of the file_buffer_list (list of DICOM files)
    and places the pseudonymised files in to a set of zips, each less than 50 MBytes.
    Those zips are then made available for download through a set of links in the
    streamlit.sidebar

    The 50MByte limit is imposed by the href download link limit.

    The compression used is DEFLATE, but the uncompressed contents are kept at just under 50 MBytes
    If a single original uncompressed file is > 50MByte, and does not compress to under 50 MByte
    that file will fail to be made available for download, and may cause the entire pseudonymisation
    attempt to fail.

    Parameters
    ----------
    file_buffer_list : list
        DICOM files that were uploaded using streamlit.file_uploader

    Returns
    -------
    zip_path_list : list
        a list of full paths to the Zipped, pseudonymised files.
        If the io.BytesIO() approach is used (current default), the list will be empty
    """

    zip_path_list: List = list()
    if file_buffer_list is not None and len(file_buffer_list) > 0:
        my_date_time = datetime.datetime.now()
        str_now_datetime = my_date_time.strftime("%Y%m%d_%H%M%S")
        zipfile_basename = f"Pseudonymised_{str_now_datetime}"

        bad_data = False
        index_to_fifty_mbyte_increment = _gen_index_list_to_fifty_mbyte_increment(
            file_buffer_list)

        st.write(index_to_fifty_mbyte_increment)

        zip_count = 0
        start_index = 0
        for end_index in index_to_fifty_mbyte_increment:
            if start_index == end_index:
                break
            zip_count += 1
            zipfile_name = f"{zipfile_basename}.{zip_count}.zip"
            zipfile_path = DOWNLOADS_PATH.joinpath(zipfile_name)
            zip_bytes_io = io.BytesIO()
            bad_data = _zip_pseudo_fifty_mbytes(
                file_buffer_list[start_index:end_index],
                str(zipfile_path),
                zip_bytes_io=zip_bytes_io,
            )
            start_index = end_index
            if bad_data:
                if zip_bytes_io is not None:
                    zip_bytes_io.close()
                    del zip_bytes_io
                else:
                    remove_file(zipfile_name)
                st.text("Problem processing DICOM data")
                return list()
            else:
                if zip_bytes_io is not None:
                    link_to_zipbuffer_download(zipfile_name,
                                               zip_bytes_io.getvalue())
                    zip_bytes_io.close()
                    del zip_bytes_io
                else:
                    link_to_zip_download(pathlib.Path(zipfile_path))
                    zip_path_list.append(zipfile_path)

    return zip_path_list
示例#21
0
def mosaiq_input_method(patient_id="", key_namespace="", site=None, **_):
    mosaiq_details = _config.get_mosaiq_details()

    mosaiq_site = st_misc.site_picker("Mosaiq Site",
                                      default=site,
                                      key=f"{key_namespace}_mosaiq_site")

    server = mosaiq_details[mosaiq_site]["server"]
    st.write(f"Mosaiq Hostname: `{server}`")

    sql_user = keyring.get_password("MosaiqSQL_username", server)
    st.write(f"Mosaiq SQL login being used: `{sql_user}`")

    patient_id = st.text_input("Patient ID",
                               patient_id,
                               key=f"{key_namespace}_patient_id")
    st.write(patient_id)

    cursor = st_mosaiq.get_mosaiq_cursor(server)

    if patient_id == "":
        return {}

    patient_name = get_patient_name(cursor, patient_id)

    st.write(f"Patient Name: `{patient_name}`")

    patient_fields = get_patient_fields(cursor, patient_id)

    st.write("""
        #### Mosaiq patient fields
        """)

    patient_fields = patient_fields[patient_fields["monitor_units"] != 0]
    st.write(patient_fields)

    field_ids = patient_fields["field_id"]
    field_ids = field_ids.values.tolist()

    selected_field_ids = st.multiselect("Select Mosaiq field id(s)",
                                        field_ids,
                                        key=f"{key_namespace}_mosaiq_field_id")

    cursor_and_field_ids = [(cursor, field_id)
                            for field_id in selected_field_ids]
    deliveries = _deliveries.cached_deliveries_loading(
        cursor_and_field_ids, _deliveries.delivery_from_mosaiq)
    identifier = f"{mosaiq_site} Mosaiq ({', '.join([str(field_id) for field_id in selected_field_ids])})"

    return {
        "site": mosaiq_site,
        "patient_id": patient_id,
        "patient_name": patient_name,
        "data_paths": [],
        "identifier": identifier,
        "deliveries": deliveries,
    }
示例#22
0
文件: _trf.py 项目: lc52520/pymedphys
def trf_input_method(patient_id="", key_namespace="", **_):
    """Streamlit GUI method to facilitate TRF data provision.

    Notes
    -----
    TRF files themselves have no innate patient alignment. An option
    for TRF collection is to use the CLI tool
    ``pymedphys trf orchestrate``. This connects to the SAMBA server
    hosted on the Elekta NSS and downloads the diagnostic backup zips.
    It then takes these TRF files and queries the Mosaiq database using
    time of delivery to identify these with a patient id (Ident.Pat_ID1)
    and name.

    As such, all references to patient ID and name within this
    ``trf_input_method`` are actually a reference to their Mosaiq
    database counterparts.
    """
    FILE_UPLOAD = "File upload"
    INDEXED_TRF_SEARCH = "Search indexed TRF directory"

    import_method = st.radio(
        "TRF import method",
        [FILE_UPLOAD, INDEXED_TRF_SEARCH],
        key=f"{key_namespace}_trf_file_import_method",
    )

    if import_method == FILE_UPLOAD:
        selected_files = st.file_uploader(
            "Upload TRF files",
            key=f"{key_namespace}_trf_file_uploader",
            accept_multiple_files=True,
        )

        if not selected_files:
            return {}

        data_paths = []
        individual_identifiers = ["Uploaded TRF file(s)"]

    if import_method == INDEXED_TRF_SEARCH:
        try:
            indexed_trf_directory = _config.get_indexed_trf_directory()
        except KeyError:
            st.write(
                _exceptions.ConfigMissing(
                    "No indexed TRF directory is configured. Please use "
                    f"'{FILE_UPLOAD}' instead."))
            return {}

        patient_id = st.text_input("Patient ID",
                                   patient_id,
                                   key=f"{key_namespace}_patient_id")
        st.write(patient_id)

        filepaths = list(
            indexed_trf_directory.glob(f"*/{patient_id}_*/*/*/*/*.trf"))

        raw_timestamps = [
            "_".join(path.parent.name.split("_")[0:2]) for path in filepaths
        ]
        timestamps = list(
            pd.to_datetime(raw_timestamps,
                           format="%Y-%m-%d_%H%M%S").astype(str))

        timestamp_filepath_map = dict(zip(timestamps, filepaths))

        timestamps = sorted(timestamps, reverse=True)

        if len(timestamps) == 0:
            if patient_id != "":
                st.write(
                    _exceptions.NoRecordsFound(
                        f"No TRF log file found for patient ID {patient_id}"))
            return {"patient_id": patient_id}

        if len(timestamps) == 1:
            default_timestamp = timestamps[0]
        else:
            default_timestamp = []

        selected_trf_deliveries = st.multiselect(
            "Select TRF delivery timestamp(s)",
            timestamps,
            default=default_timestamp,
            key=f"{key_namespace}_trf_deliveries",
        )

        if not selected_trf_deliveries:
            return {}

        st.write("""
            #### TRF filepath(s)
            """)

        selected_files = [
            timestamp_filepath_map[timestamp]
            for timestamp in selected_trf_deliveries
        ]
        st.write([str(path.resolve()) for path in selected_files])

        individual_identifiers = [
            f"{path.parent.parent.parent.parent.name} {path.parent.name}"
            for path in selected_files
        ]

        data_paths = selected_files

    st.write("""
        #### Log file header(s)
        """)

    headers = []
    tables = []
    for path_or_binary in selected_files:
        try:
            path_or_binary.seek(0)
        except AttributeError:
            pass

        header, table = read_trf(path_or_binary)
        headers.append(header)
        tables.append(table)

    headers = pd.concat(headers)
    headers.reset_index(inplace=True)
    headers.drop("index", axis=1, inplace=True)

    st.write(headers)

    deliveries = _deliveries.cached_deliveries_loading(
        tables, _deliveries.delivery_from_trf)

    identifier = f"TRF ({individual_identifiers[0]})"

    patient_name = _attempt_patient_name_from_mosaiq(headers)

    return {
        "site": None,
        "patient_id": patient_id,
        "patient_name": patient_name,
        "data_paths": data_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }