ImagingDataCommons / highdicom

High-level DICOM abstractions for the Python programming language
https://highdicom.readthedocs.io
MIT License
179 stars 37 forks source link

How do I enter free text in a TID 1501? #124

Open seandoyle opened 3 years ago

seandoyle commented 3 years ago

In row 12 of TID 1501 it appears that text entries can be added to the object; the Content Item Description for this line states Allows encoding a flat list of name-value pairs that are coded questions with coded or text answers, for example, to record categorical observations related to the subject of the measurement group. A single level of coded modifiers may be present.. What is the recommended way to add these values?

If I create a MeasurementsAndQualitativeEvaluations object containing QualitativeEvaluations of the sort

    text_item = QualitativeEvaluation(
        name=CodedConcept(
            value='121071',
            meaning='Finding',
            scheme_designator='DCM',
        ),
        value=CodedConcept(
            value=text,
            meaning='Finding',
            scheme_designator='DCM',
        )
    )

this will work (and pass SR validation) until the size of the text exceeds 16 characters (after that there is an exception in coding.py). This may also be considered an abuse of CodedConcept? Or perhaps there is a way to include aTextContentItem but I don't see the way to do this.

The use case is to permit free text additions to an SR by a radiologist for findings not present in the original SR generated by the model output. These text findings are at coded anatomic finding sites.

CPBridge commented 3 years ago

Hi @seandoyle, I imagine when @hackermd wrote this he was being opinionated and wanted to force users to use values from a controlled terminology rather than free text, even though the latter is allowed by the standard. I would probably err on the side of agreeing with that.

If you want to force inclusion of a free text evaluation, I would definitely not take the above approach. Instead I would construct the measurements group object without the evaluation, then separately create a TextContentItem and manually append it to the ContentSequence of the first (and only) content item of the created template (representing the container). Something like this:

grp = hd.sr.PlanarROIMeasurementsAndQualitativeEvaluations(
    ...
)
text_item = hd.sr.TextContentItem(
   ...
)

grp[0].ContentSequence.append(text_item)
hackermd commented 3 years ago

Yes, @CPBridge is right. I wanted to strongly discourage the use of free text for qualitative evaluations.

seandoyle commented 3 years ago

Thanks - I agree in general with discouraging free text but the app that I'm creating permits radiologists to enter text (this is their requirement) and don't want to generate a second data object for capturing their output. I'll try @CPBridge's approach and validate it with the pixelmed SR validator.

fedorov commented 3 years ago

This feature will be helpful for us in the future as well, thanks for bringing this up @seandoyle! When we worked on the PI-RADS family of templates, we deliberately made the decision not to codify everything that the guidelines mention or allow to capture - that would be an enormous effort, and the guidelines are under-defined, requiring interviews and iterations with the domain experts to identify and finalize the codes. Codifying makes sense when the concepts are well-established and there is broad consensus for the specific use case. Otherwise, this is (at least for some use cases) a huge and potentially counterproductive effort.

I understand that allowing free text opens the door for not using the codes at all, but I think this is a better evil than significantly increasing the complexity of the template and introducing coded concepts that have not reached consensus, and also completely removing the possibility of describing something that cannot be anticipated and is not covered by the codes.

CPBridge commented 3 years ago

Implementing this in a backwards compatible way could get a bit messy. We'd probably need to create a new, alternative TextQualitativeEvaluation, or similar, and then accept Sequence[Union[QualitativeEvaluation, TextQualitativeEvaluation]] for the qualitative_evaluations parameter of the measurement group constructors. It's also true that currently the parsing API won't return content items of value type TEXT for the get_qualitative_evaluations method

hackermd commented 3 years ago

Another alternative would be use a private (potentially project-specific) coding system. I would prefer that over using TEXT. What do you think @fedorov @pieper @CPBridge @seandoyle?

fedorov commented 3 years ago

Using codes (private or public) assumes that you know what you expect to find in advance. Using private codes just eliminates the burden of finding a standard code. How would you, for example, solve the issue of describing incidental findings using private codes?

seandoyle commented 3 years ago

@hackermd - do you mean like I did in the first message on this thread? The problem (perhaps a small implementation problem) is that in when a value with a length > 16 gets added it is assigned to a 'LongCodeValue' instead of a 'CodeValue' which leads to an AttributeError being generated on coding.py because there is no CodeValue attribute.

Or perhaps you mean something different?

hackermd commented 3 years ago

Using codes (private or public) assumes that you know what you expect to find in advance. Using private codes just eliminates the burden of finding a standard code. How would you, for example, solve the issue of describing incidental findings using private codes?

I have only really considered automated systems, which need to choose terms from a predefined terminology. This may be different for user interfaces, which need to handle arbitrary user input.

hackermd commented 3 years ago

Implementing this in a backwards compatible way could get a bit messy. We'd probably need to create a new, alternative TextQualitativeEvaluation, or similar, and then accept Sequence[Union[QualitativeEvaluation, TextQualitativeEvaluation]] for the qualitative_evaluations parameter of the measurement group constructors. It's also true that currently the parsing API won't return content items of value type TEXT for the get_qualitative_evaluations method

We could call those TEXT content items "descriptions" rather than "evaluations" and add a descriptions parameter to the constructor as well as a corresponding get_descriptions method to the class.