Jump to content

Converting Scientific Notation to Real


Recommended Posts

Sometimes when you use GetRField() to return a dimension value from a PIO, it returns the value in scientific notation, so a value of 900 (mm) becomes 9e02. You can use Str2Num('9e02') to convert this to a real number, however this does not work in python and produces this error:

 

Type Error. Can't convert 'float' object to str implicitly.

 

Here is a code snippet:

 

perimValue = vs.Str2Num(vs.GetRField( h, 'Space', 'Perim' ))

crit_ = "('Space'.'Perim' = "+ perimValue + ")"

vs.ForEachObject(DoIt, crit_)

 

The equivalent in Vectorscript works OK.

 

Thanks for any ideas.

 

Julian

Link to comment

Julian,

 

That error message makes me think it is already a Number (type Float) and that the problem is that Python can't convert the float into a string which is the required input of the Str2Num.

 

Perhaps use something like 

 

If Type ( vs.GetRField(.......)) = str then PerimValue=Num2Str(GetRField(.......)) else PerimValue = GetrRField(.......) 

Link to comment

Well I guess you are correct Pat, and thanks for your reply. It is already a number expressed in scientific notation, but that can't be used in a criteria string. This is the error it gives:

 

Error: Unable to parse Search Criteria.

Database(('Space'.'Perim' = 9e02))

 

so I need a way to change this:

 

perimValue = 9e02

 

to this:

 

perimValue = 900

 

Any ideas on that one?

Link to comment

The quotes around the 9e02 are forcing it to a sting instead of a number. Also, the format command needs to be used in conjunction with an assignment (I think).

 

widthValue = 9e02
widthValue = format(widthValue, '.0f')
vs.Message(widthValue)

 

the .0 forces it to zero decimal places. Leave that off and the default is 6 decimal places. OK if you are doing a greater than/less than. Not so good if you are doing an equals.

 

Link to comment

PS. I really much prefer the mandatory typing of variables in Vectorscript. It makes sure you know what kind of a result you are getting.

 

And I really hate using white space as block delimiters. Being/End are so much easier to read.

 

Overtime i have to work in Python I feel like I am back in Fortran in 1983 and counting columns on a punch card.

 

Link to comment

I totally agree Pat. Even though Pascal is verbose compared to Python and doesn't have the same community support or external libraries, it requires special knowledge to understand the syntax.

 

Anyway thanks to you I figured a way to do it, though it only works with files in metric units. If you draw a Space, leave it selected the run this script, you will see the desired criteria string:

 

perimValueStr = vs.GetRField( vs.FSActLayer(), 'Space', 'Perim' )
(Flag, perimValue) = vs.ValidNumStr(perimValueStr) #convert notation string to real number
perimValueStr = format(perimValue, '.4f') #convert real back to string to 4 decimal places
crit_ = "('Space', 'Perim' = "+ perimValueStr + ")" 
vs.Message(crit_)

 

 

Link to comment

You can use float() to go straight from the string value to a decimal. repr() will convert back to a string if you need that for the criteria. It should also ignore any white space. 

 

repr(float(perimValueStr)) will do it in one go. 

 

eval() also works well to convert a string into whatever python variable type best matches. 

Link to comment

Thanks for the suggestion Josh. Unfortunately it doesn't work as the string remains in scientific notation.

 

If you draw a Space object in a file with units set to mm then run this script:

 

    perimValueStr = vs.GetRField( vs.FSActLayer(), 'Space', 'Perim' )
    repr(float(perimValueStr))
    crit_ = "('Space', 'Perim' = "+ perimValueStr + ")" 
    vs.Message(crit_)

 

you will get this result:

 

    ('Space', 'Perim' = 6.4e03)

 

If the units are changed to Ft & Ins, then it doesn't work at all and produces an error (could not convert string to float) as the notation value is too long.

 

Link to comment

Lots of special cases here.

 

The GetRField returns a value. In the case of units of mm, you get something back that Python interprets as a number (but in scientific notation). If you return feet and inches, it includes the unit marks and returns something that Python considers to be a string.

 

I have not tested it, but I would bet that if you had the unit mark turned on for mm, it would probably return something that python would consider to be a string also.

 

So, you either need to do special case for everything, or possibly turn on show units, run the script and then turn off show units. That way you should always end up with a value returned that is a string, so at least you don't have to fight with some returns as numbers and some as strings.

 

But if you can live with just mm, try this:

 

perimValue = (vs.GetRField( vs.FSActLayer(), 'Space', 'Perim' ))
perimValueStr = format(float(perimValue),'.4f')
crit_ = "('Space', 'Perim' = "+ perimValueStr + ")" 
vs.Message(crit_)

 

 

Link to comment

I had forgot about units.  In that case vs.ValidNumStr us the way to go, and should compensate for any units format.  That should take care of Pat's concern about special cases.  Using it in a function lets you easily return 0 VS can't convert the value.

 

def Str2Num(inStr):
    success, outNum = vs.ValidNumStr(inStr)
    if success:
        return outNum
    else:
        return 0

 

eval() and repr() return values, not converting the argument, which is why repr(float(perimValueStr)) as it's own line wasn't working.  If you define the above function, the one line version would be:

crit_ = "('Space', 'Perim' = "+ repr(Str2Num(perimValue)) + ")" 

 

This should give you a value without units, which is I believe what you want for the criteria.  If you need a dimension-formatted string, then you need to deal with escaping foot and inch marks.  I haven't tested much with python yet, but with native VS, 2018 is much more finicky about quotation marks in criteria strings.

Link to comment

Thanks Pat and Josh. I think Josh has nailed it with his last suggestion, which seems to work with any units. The script I am working on is for a worksheet and will populate a single cell with all the door IDs that match a particular door type (and optionally width), comma separated. A door type could be an internal door, an external door, the front door of an apartment, or a patio door of a particular style. Sometimes the doors can vary in size but are otherwise the same type. Something like this:

 

    TYPE                ID                   WIDTH     ETC

|  Type A   |   D01, D04, D07   |   1000   |             |

|  Type A   |   D02, D03, D05   |    900    |             |

|  Type B   |   D06, D11, D12   |   1000   |             |

|  Type B   |   D08, D09, D13   |    900    |             |

 

The RunScript() function is so powerful it has prompted me to dip my toes into the python pit.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...