Ejemplo n.º 1
0
def mosaiq_input_method(patient_id="", key_namespace="", **_):
    mosaiq_details = get_mosaiq_details()
    site_options = list(mosaiq_details.keys())

    mosaiq_site = st.radio("Mosaiq Site",
                           site_options,
                           key=f"{key_namespace}_mosaiq_site")
    server = mosaiq_details[mosaiq_site]["server"]
    f"Mosaiq Hostname: `{server}`"

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

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

    cursor = get_mosaiq_cursor(server)

    if patient_id == "":
        return {}

    patient_name = get_patient_name(cursor, patient_id)

    f"Patient Name: `{patient_name}`"

    patient_fields = get_patient_fields(cursor, patient_id)
    """
    #### Mosaiq patient fields
    """

    patient_fields = patient_fields[patient_fields["monitor_units"] != 0]
    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 = cached_deliveries_loading(cursor_and_field_ids,
                                           delivery_from_mosaiq)
    identifier = (
        f"Mosaiq ({', '.join([str(field_id) for field_id in selected_field_ids])})"
    )

    return {
        "patient_id": patient_id,
        "patient_name": patient_name,
        "data_paths": selected_field_ids,
        "identifier": identifier,
        "deliveries": deliveries,
    }
Ejemplo n.º 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()
Ejemplo n.º 3
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,
    }
Ejemplo n.º 4
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
Ejemplo n.º 5
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()
Ejemplo n.º 6
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
Ejemplo n.º 7
0
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,
    }