gnumed-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Gnumed-devel] re: experimental editor - further comments


From: Richard Terry
Subject: Re: [Gnumed-devel] re: experimental editor - further comments
Date: Sun, 04 Jul 2004 18:40:32 +1000
User-agent: Mozilla Thunderbird 0.6 (X11/20040503)

Why not just forget complicating this and follow the logical steps I've outlined below. The wxWigits can to be best of my memory be resized on the fly, but that is not really the issue, because if you allow enough blank space in the editor in the first place you will have lots of spare screen real-estate. All you will be doing is shuffling down the SOAP lines as need dictates.

Why not just try what I've suggested in stages, ie make the editor with the four words in it, and work out how to capture the mouse clicks so that when the user first clicks on it the cursor is directed to the space after the line nearest to where he clicked. Allow typing to the end. Allow hitting the enter key to drop the cursor to the next line etc.

I really think you are complicating something quite simple. I always found when developing in VB that I'd do the basic outline first, and incrementally add the features. That way development is de-bugged along the way as features are added.

Regards

richard

sjtan wrote:

Richard Terry wrote:

I would be far more elemental than that.

I can send in some basic specs. I would not try to make anything which plugs into the gui framework or loads or saves data for starters.

Simply a stand along wxPython frame contining a modified editor such as that in the wxPython demo, where we see how hard it is to make 'out of bounds' some areas of the lines ie functionally is like this.
1)Frame contains the editor
2)Editor and controls and  looks like this and contains this text
______________________________
|  Subjective   :                                 |
|  Objective    :                                 |
|   Assessment:                                 |
|   Plan           :                                |
______________________________
                           [btn_ok] [btn_cancel]

===============================
list heading = "There are n SOAP elements this consultation" (n = listindex +1)
=========================================
wxList


================================



Need array to contain inputted data eg textinput() with 0-3 elements
Inital code should do the following.



-white background of editor
- Text foreground prompts RGB 0,0, 131


ok, aesthetics?

- If user clicks anywhere over the edit area prompts the cursor should be re-directed to the first character space on the corresponding line (or the end of any existing characters on that line)


ok, rapid entry

- If user types on line allow input to end of line



-If text exists on line and enter key pressed, cursor is re-set to start of next line underneath
-If on Plan line and enter pressed then give focus to the Ok button


not hard to do, but what if you need more space for S/ or O/ ?

-If Text exists on 1 or more lines of editor and ok button clicked then save text




if textinput(0) will contain any text on the Subjective line (excluding the subjective heading) (1) will contain any text on Objective line (excluding the Objective heading)
  etc
After text saved to array, place a 'summary' as first element in the list array looking like below - finally invoke btn_clear to clear the editing area, and reset cursor to after 'Subjective'

ie

Before the Ok button is clicked:
______________________________
|  Subjective   : earache                     |
|  Objective    : red drum                   |
|   Assessment: middle ear infection    |
|   Plan           : script amoxil              |
______________________________
                           [btn_ok] [btn_cancel]

===============================
    There are  0 SOAP elements this consultation
=========================================
wxList is empty


================================
After the Ok button is clicked:
______________________________
|  Subjective   :                               |
|  Objective    :                               |
|   Assessment:                               |
|   Plan           :                              |
______________________________
                           [btn_ok] [btn_cancel]

===============================
    There are  1 SOAP elements this consultation"
=======================================
wxList now contains
Middle Ear Infection - (earache, red drum, Plan:script amoxil)

================================

Now one additional functionality.

If the user clicks on this item the list, you replace the strings in the array(0-3) back into the corresponding lines of the editing area.

This should be fairly simple to anyone who can program. If you get to that point you have the whole thing beat. At no point try and save the data or link to the database.

The next clever thing to do is the following:

Starting with this:
_______________________________
|  Subjective   : earache                     |
|  Objective    : red drum                   |
|   Assessment: middle ear infection    |
|   Plan           : script amoxil              |
______________________________

Make this happen when the text reaches the end of the line:
_______________________________
|  Subjective   : earache, fever, cough, |
|                      vomiting, rash            |
|  Objective    : red drum                   |
|   Assessment: middle ear infection    |
|   Plan           : script amoxil              |
______________________________

Ie you will have to 'shift down' the prompts and insert a blank line in the editor as the users text gets to the end of the line. (similarly you will have to delete a blank line if one is made blank by deleting text). There are scads of ways to do this. When I did my text mode text and graphics editor I just kept a map of where this were, and inserted blank lines into the control via code as needed, I don't know how wxPython handles this.


ok, this might be easy in some gui environment that allow resizing of widgets. I don't know if resize works in wxWidgets ,
but I'll take a look. If it doesn't work, there are several workarounds .

- the most flexible is to do what Swing did with AWT in java, and reimplement a widget ontop of a drawing area, and take care of events at the lowest level, e.g. mouse movements, clicks, keyboard input.


Once you've acheieved this the whole thing is beaten. Next step is to add some smart promtps eg BP= (inserted at the cursor by a control key - but colour code them) and only allow this type of things on Objective lines. Next thing is to use the phrase wheel code to auto-complete.

Can you enumerate the smart prompts you are thinking of , what key bindings they'll be? Is it e.g. ctrl-A B -> BP , ctrl-A T - Temp , Ctrl-A R resp examination mini-form .
I need to get an idea of the scope of "smart prompting"


Frankly, when I use MD, I just like typing a quick note and add in my s/ o/ a/ p/ labels with the keyboard ( or no labels really, a carriage return will do)

s/ 2 days l earache, fever, tummy pain ; iutd; no phx, nka, no meds curr, not had panadol, o/e wt 15kg , T 38.5 ears dull, r > l, throat nad , chest clear, abdo lax nontender
a/ ?r otitis media ? urti
p/ 24 hr delay antis, amoxil 250mg tds delayed script. panamax 240/5 4ml qid , r/v 1-2/7

What I'd like the computer to do is parse this for me , mainly the script really.

Sometimes I'll scrawl the history, and then bring up MD's click as systems examination tabbed dialog, which isn't too bad, and do it that way, but touching the mouse breaks the flow of typing (which is a good excuse not to talk with the patient, and pretend you're alone just
dealing with a computer ).



The idea I had in mind is that in the P/ part, if you type script- amoxil 500mg tds , panamax 1g qid prn, imz - fluvax l s/c deltoid given, Ix - lipids, glucose, psa , ref - ongoing Mr Jones ENT, it adds action items on a tree to the right of the edit area. These action items have a "do" hyperlink, and there might be a "do all" hyperlink, and when that is clicked, a confirmation of action dialog is brought up, with the actions listed, whether they go to the printer, how many pages each item takes, which printer the item goes to / or alternatively a item will be sent as a request message electronically to a third party. Some actions might be "planned" or scheduled in the future, and they just need confirmation for adding to the "TODO" part of the patient's medical record.

Regards

Ricahrd

I'll need to look at the phrasewheel code again. I don't think the phrasewheel code is that easy to use, except when dealing with plugged in phrase wheel matchers written by Karsten ( it's his design, so it's easiest for him to do phrasewheel configuration). Many of them are direct to sql bound matchers, but I think eventually K will come up with business object intermediate matchers , e.g. because they provide for caching better.


Another old idea is to do a text only version of this clinical editor , no wx stuff at all, so that the functionality can be worked out first, and then add the gui acrobatics later. I've been playing around with the regex re package again. Regular expressions is a kind of language for parsers. it's like looking for "*.doc" files in dos command line, only it's more expressive.
In summary  this is its syntax:

.   is any character.
\w is a word alphanumeric character.  \W  is any non word character
\d  is a digit character. \D is any non digit character
\s is a whitespace character (including tabs). \S is any non white space character

* is 0 or more occurences of the previous regex expression, + is 1 or more , and ? is 0 or 1 occurence.

() means everything inside the brackets is one regex expression, and also means anything that matches the regex inside the brackets will be treated as a GROUP ; when there are multiple nested groups like ( ((\w+)(\d+))\w+) the outer group is group 0, the next inner 2 groups are groups 1, and 2, and the innermost groups are 3, and 4.

The attached program uses regex to try to match keyed patterns, and returns the category key to which the a pattern matches. So you can use regex for categorising items, and if you have a nested structure, the categories could be heirarchical.

e.g. try typing >" 3 days headache, runny nose, cough; requests medical certificate"

So in this example, you can get a reason category, a duration , and symptoms by systems list of the S/ text that is typed.


The re package is in the python html documentation , under the library section.

The main re commands are :

my_re_prog= re.compile( re_expression)

my_re_prog.findall( input_text) returns all the text that matches in the input text , starting anywhere.

my_re_prog.search( input_text) returns a match object do which further commands can be issued to examine the result ( in the re python html documentation).


now, if I knew how to implement the re package, then I'd consider myself a good programmer.



------------------------------------------------------------------------


site=   [ 'finger', 'wrist', 'thumb', 'hand', 'forearm', 'elbow', 'arm', 
'shoulder', 'neck', 'back', 'lumbar', 'thoracic', 'ribs', 'sacral', 'pelvis', 
'side', 'loin', 'hips', 'thigh','hamstring', 'groin', 'knee', 'shin', 'calf', 
'ankle', 'heel', 'foot', 'toe', 'bottom', 'bum', 'eyelid', 'ear canal', 
'(pinna|ear helix|helix\s*\w*\s+ear)']

mskSite = ''.join(('(', '|'.join(site),')'))
pain='(sore\w*|pain\w*|hurt\w*|ache\w*)'
discharge='(discha\w+|runn\w+|sticky|gummy|water\w*)'
blood='((bleed\w*)|(blood\w*))'
immune='((vacc\w*)|(immun\w*))'
lac='((lac\w*)|cut|(wound\w*))'
absc='(boil|infect\w*|abscess\w*)'
lump='(lump|swelling|mass)'
i_time='(((\d+|few|some|many)\s*((day\w?)|(d)\s|(wk\w*)|(wee\w+)|(mo\w*)|(mnt\w*)|(yr\w*)|(year\w*)){1}))'

s = [ 'reason', 'gen', 'cvs', 'rs', 'gi', 'ug', 'cns', 'msk', 'skin' , 'ent', 
'opth', 'gyn']

s1= [ ('duration', [i_time]), ('reason', ['med\w*\s+cert\w*', 'workcover', 'taxi\s+lic\w+', '((emp\w*|work)\s+(med\w*|phys\w*))|((exam\w*)|(assess\w*))', 'script\w*', 'checkup|(rev\w*)', '('+immune+'\s+'+i_time+')','('+i_time+'\s+'+immune+')' ,'(accid\w*)|(injur\w*)', 'unwell' ] ), ('gen', ['hot', 'cold', 'feve\w+|febrile', 'weak\w+', 'tired', 'yellow|jaund\w+', 'pale|pall\w+', 'unwell', '(low)|(w\w*t loss)|(loss of w\w*t)'] ) ,( 'cvs', ['chest pain', 'palpitations', 'soboe', 'blackout', 'dizz', 'faint', 'bp' ] ), ('rs' , ['sob', 'cough', 'phlegm', 'wheeze', 'pleuritic', '(tight\w*|chest\w*){2}'] ),
        ('gi' , ['central\s+abdo','epigastric', 'ruq','lif', 'rif', 'luq', 
'(abdo\w+\s+pain)', 'heartburn|reflux', 'regurg', 'vomit', 'naus', 'diarrh', 
'constip', '(abdo\w+|upset){2}', '(alt.+bowel)|(bowel.+alt\w+)', 
'change.+bow\w+', 'bow.+change\w*', 
'((incr\w+|decr\w+|fewer|more|less)|(bowel\s+mot\w+|move\w+))', 'pr bleed', 
'coffee grounds', 'black.*motion'] ),
        ('ug', ['blood.*urine', 'haematuria', 'urgency', 'frequency', 
'dysuria', 'hesitancy', 'nocturia']  ),
        ('cns', ['headache', 'dizziness', 'numbness', 'weakness', 'stiffness', 
'tremor', 'difficult|walk', 'fall', 'photophob', 'neck stiff', 'one|sided'  ] ),
('msk' , [ mskSite + '\s+'+pain , pain+'\s+'+mskSite , mskSite + '\s+'+blood, blood+'\s*\w*\s+'+mskSite , mskSite + '\s+'+lac, lac+'\s*\w*\s+'+mskSite , mskSite + '\s+'+absc, absc+'\s*\w*\s+'+mskSite , mskSite + '\s+'+lump, lump+'\s*\w*\s+'+mskSite , '(myalgia)|(musc\w+\s+'+pain+')', 'weak\w+'
                         ] ),
('ent' ,[ 'dry throat', '('+pain+'\s+throat)' , '(throat\s+'+pain+')', '(coryza|run\w+\s+nose)' '(ear\s*'+pain+')', '('+pain+'\s+ear'+')', '(ear\s*'+discharge+')', '('+discharge+'\s+ear'+')' , '(nose\s*'+pain+')', '('+pain+'\s+nose'+')', '(nose\s*'+discharge+')', '('+discharge+'\s+nose'+')' '(nose\s*'+blood+')', '('+blood+'\s+nose'+')' ] ), ('opth', [ '(eye\s*'+pain+')', '('+pain+'\s+eye'+')', '(eye\s*'+discharge+')', '('+discharge+'\s+eye'+')', '(eyelid\s*'+pain+')', '('+pain+'\s+eyelid'+')' ]
                         ),
         ('gyn', [      
                         '(no period|amenorrh\w+|late period)',
                         '(menorrhagia|heavy period|dub|period\s? too 
long|period\s? too heavy)',
                         '(recent (prog\w*\s+)?implant|recent depot prog\w+)',
                         'frequent periods',
                         'infrequent periods',
                         'pelvic pain',
'(period pains|painful period|dysmenorrh\w+)' ]
                                ) ]
re_map = {}
import re
for (k,x) in s1:
        re_map[k]= []
        for y  in x:
                print y, k
                re_map[k].append ( re.compile(y) )
        

while 1:
        inp = raw_input('>')
        model = []
        for k,v in re_map.items():
                for r in v:
                        terms = r.findall(inp)
                        if terms <> []:
                                model.append( (k, (terms, r.pattern) ) )
        
        print "The Model found was ", model
        
        
        
        








reply via email to

[Prev in Thread] Current Thread [Next in Thread]