2

I'm trying to export data in a certain format (.cube file); the file type isn't the main issue.

Now I have to print different line formats based on their line number. So far so good, I'm able to do it using the following:

 if line_num == 0 or line_num == 1:
     # comment line
     output_file.write("%s\n" % (self.comments[line_num]))
     continue
 if line_num == 2:
     # number of total atoms, and the origin coordinates
     output_file.write("%4d %.6f %.6f %.6f\n" % (self.num_atoms, self.origin[0], self.origin[1], self.origin[2]))
     continue

The above work, but I've wanted to use the '%' operator in the following manner:

if line_num == 2:
     # number of total atoms, and the origin coordinates
     output_file.write("%4d %.6f %.6f %.6f\n" % (self.num_atoms, self.origin)

because self.origin is a Numpy Array size 1X3.

When doing so, I get the following error:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: only size-1 arrays can be converted to Python scalars

is there a way to do what I wanted instead of give every element in the array.

Thanks.

6
  • 4
    Try *self.origin Commented May 2, 2019 at 7:06
  • 1
    In addition to @Barmar advise - get using new-style string formatting or f-strings in 3.6+ pyformat.info Commented May 2, 2019 at 7:09
  • @buran How would he do this with f-strings? Wouldn't that require him to write {self.origin[0]} {self.origin[1]} {self.origin[2]}, which is what he's trying to simplify? Commented May 2, 2019 at 7:12
  • yes, in this particular case it would be better to use str.format() method and star-unpack self.origins. On other hand - they still has to have format placeholders for every element of self.origin. It may be better to convert self.origins to str beforehand and have just two format placeholders. My advise was more general - to move away from old-style string formatting, more over they use python 3 Commented May 2, 2019 at 7:19
  • 1
    Using iterable unpacking (*self.origin) works in Python 3, but not in Python 2. In Python 2, you actually have no choice but to write out the entire thing (self.origin[0], self.origin[1], self.origin[2]). Commented May 2, 2019 at 7:22

3 Answers 3

4

Use *self.origin to unroll the array.

>>> "%4d %.6f %.6f %.6f\n" % (num_atoms, *origin)
' 199 1.000000 2.000000 3.000000\n'
>>> 
Sign up to request clarification or add additional context in comments.

5 Comments

Ive tried but I get the following: File "<stdin>", line 1 SyntaxError: can't use starred expression here might it be python3 issue?
noted! is there away that works for both py2 and py3?
Hi @EE_student_TAU, check my answer below, should work for both python2 and python3
@EE_student_TAU it's alright if you wanna have have something be backwards compatible but for new code there's no reason to target python2 seeing how it's going to be deprecated in a few months: pythonclock.org
1

The issue is that self.origin is a list, and you are trying to print a list using float formatting, you can unpack the list using *self.origin and then it should work, see a simple example below.

You can use string.format which works for for both python2 and python3

origin = [1,2,3]
print("{:4d} {:6f} {:6f} {:6f}".format(1, *origin)) 
#   1 1.000000 2.000000 3.000000
Python 2.7.10 (default, Feb 22 2019, 21:17:52) 
[GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> origin = [1,2,3]
>>> print("{:4d} {:6f} {:6f} {:6f}".format(1, *origin)) 
   1 1.000000 2.000000 3.000000
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 16:39:00) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> origin = [1,2,3]
>>> print("{:4d} {:6f} {:6f} {:6f}".format(1, *origin))
   1 1.000000 2.000000 3.000000

3 Comments

Updated @1313e please check! and consider upvoting if it works
Yes, using format will work, as iterable unpacking inside a function call works in Python 2. Keep in mind that in Python 2, .format(*origin, 1) will not work as only named arguments are allowed to follow an iterable unpacking in Python 2.
Thanks for the help! would appreciate some votes also
1

In case, if someone is looking for an f string equivalent, use the following:

In [69]: arr = np.array([1.4556, 2.4, 3.3245])

# printing only 3 digits after the decimal point
In [70]: f'{" ".join(format(c, ".3f") for c in arr)}'
Out[70]: '1.456 2.400 3.325'

A diluted version of this code would be, thanks to the suggestion by NaN:

In [95]: print(("{: .3f}"*len(arr)).format(*arr))
 1.456 2.400 3.325

3 Comments

But this doesn't respect the float formatting the OP wants, how do we ensure that?
Great, I will upvote for the fix , but actually the OP wants variable formatting 4d %.6f %.6f %.6f, how can we do that, make a format array ?
for python 3... similar to the f-string but sometimes shorter …. ("{: .3f}"*len(arr)).format(*arr) … yields ' 1.456 2.400 3.325'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.