Data

How to Suppress Scientific Notation in pandas and NumPy

Data · Published 2026-10-24

Four large number keys, 4, 5, 1 and 2, on an old adding machine
Number keys on an old adding machine.

In NumPy, call np.set_printoptions(suppress=True); in pandas, set pd.set_option("display.float_format", "{:.2f}".format) (or use pd.option_context for a single block). Both only change how numbers are displayed; the stored values are untouched, and files or reports need their own formatting via to_csv(float_format=...), Styler.format or f-strings.

Why scientific notation appears

Python, NumPy and pandas each pick a representation that is short and unambiguous. Plain Python's repr() switches to exponent form when the decimal exponent is below -4 or at least 16:

print(1e16, 0.0001, 0.00001, 123456789012345678.0)
1e+16 0.0001 1e-05 1.2345678901234568e+17

NumPy formats a whole array uniformly. By default it uses scientific notation for every element when the smallest absolute value is below 1e-4 or the ratio between the largest and smallest exceeds 1e3, as described in the set_printoptions reference. One tiny value is enough to change the look of the whole array:

import numpy as np

a = np.array([0.00001234, 1.5, 123456.0])
print(a)
print(np.array([0.5, 1.5, 2.5]))
[1.23400e-05 1.50000e+00 1.23456e+05]
[0.5 1.5 2.5]

pandas formats column by column. A column switches to scientific notation when its values would not fit nicely at the current display.precision (6 by default): very large magnitudes (around 1e9 and above with default settings) or values too small to show at that precision.

import pandas as pd

df = pd.DataFrame({
    "item": ["bolt", "server", "license"],
    "unit_cost": [0.000045, 12500.0, 1.5],
    "revenue": [1.2e9, 345.67, 98765432.1],
})
print(df)
      item     unit_cost       revenue
0     bolt      0.000045  1.200000e+09
1   server  12500.000000  3.456700e+02
2  license      1.500000  9.876543e+07

df.describe() is a frequent offender because statistics such as count, std and max land in the same column with very different magnitudes.

NumPy: set_printoptions(suppress=True)

suppress=True forces fixed-point notation; precision sets the number of digits after the decimal point (default 8):

a = np.array([0.00001234, 1.5, 123456.0])

np.set_printoptions(suppress=True)
print(a)

np.set_printoptions(suppress=True, precision=3)
print(a)

np.set_printoptions(suppress=True, precision=8, floatmode="fixed")
print(a)
[     0.00001234      1.5        123456.        ]
[     0.       1.5 123456. ]
[     0.00001234      1.50000000 123456.00000000]

Notice the second line: with precision=3, 0.00001234 prints as 0.. Suppression rounds tiny values to zero in the output, which can be misleading in scientific data. floatmode="fixed" always prints exactly precision digits, which is easier to scan in columns.

Two limits worth knowing: values of 1e16 and above still print in exponent form even with suppress=True ([1.e+20 1.e+00]), and set_printoptions is global for the whole process. Calling it with no arguments does not reset anything; pass the defaults back explicitly (precision=8, suppress=False, floatmode="maxprec") or, better, use the context manager so the change is scoped:

with np.printoptions(suppress=True, precision=6):
    print(a)
print(a)  # back to the previous settings
[     0.000012      1.5      123456.      ]
[1.23400e-05 1.50000e+00 1.23456e+05]

Formatting a single NumPy value or array as text

For one number, np.format_float_positional returns the shortest positional string that round-trips, without exponent:

print(np.format_float_positional(1.234e-5))
print(np.format_float_positional(1e16))
print(np.format_float_positional(np.float32(0.1)))
print(np.array2string(a, formatter={"float_kind": lambda x: f"{x:.4f}"}))
0.00001234
10000000000000000.
0.1
[0.0000 1.5000 123456.0000]

When writing arrays to text files, np.savetxt takes a fmt argument: np.savetxt("out.txt", a, fmt="%.8f") writes 0.00001234, 1.50000000, 123456.00000000. Its default "%.18e" is scientific.

pandas: display.float_format

pandas' options system accepts a callable that turns each float into a string. A bound str.format method is the usual idiom:

pd.set_option("display.float_format", "{:.6f}".format)
print(df)

pd.set_option("display.float_format", "{:,.2f}".format)
print(df)

pd.reset_option("display.float_format")
      item    unit_cost           revenue
0     bolt     0.000045 1200000000.000000
1   server 12500.000000        345.670000
2  license     1.500000   98765432.100000
      item  unit_cost          revenue
0     bolt       0.00 1,200,000,000.00
1   server  12,500.00           345.67
2  license       1.50    98,765,432.10

The format applies to every float column, so pick one that suits all of them; above, two decimals hides the bolt's unit cost entirely. Raising display.precision (for example pd.set_option("display.precision", 10)) is a gentler alternative: small values get enough digits to be shown in fixed notation, but large values may still switch to exponents.

Scoped changes with option_context

In notebooks and libraries, avoid changing global state. pd.option_context applies options only inside a with block:

with pd.option_context("display.float_format", "{:.4f}".format):
    print(df)
print(df)
      item  unit_cost         revenue
0     bolt     0.0000 1200000000.0000
1   server 12500.0000        345.6700
2  license     1.5000   98765432.1000
      item     unit_cost       revenue
0     bolt      0.000045  1.200000e+09
1   server  12500.000000  3.456700e+02
2  license      1.500000  9.876543e+07

Per-column formatting for reports: Styler.format

When different columns need different formats (and you are producing HTML, a notebook view or Excel output), use the Styler. It requires jinja2 and leaves the DataFrame unchanged:

styled = df.style.format({"unit_cost": "{:.6f}", "revenue": "{:,.2f}"})
html = styled.to_html()        # or display(styled) in Jupyter, styled.to_excel(...)

For plain-text output with per-column formats, convert the columns to strings explicitly; just remember the result is no longer numeric:

print(df["revenue"].map("{:,.2f}".format).tolist())
['1,200,000,000.00', '345.67', '98,765,432.10']

Writing files: to_csv(float_format=...)

Display options have no effect on files. to_csv writes the shortest round-tripping repr, which includes exponents for small numbers:

df.to_csv("report.csv", index=False)
df.to_csv("report.csv", index=False, float_format="%.6f")
item,unit_cost,revenue
bolt,4.5e-05,1200000000.0
server,12500.0,345.67
license,1.5,98765432.1

item,unit_cost,revenue
bolt,0.000045,1200000000.000000
server,12500.000000,345.670000
license,1.500000,98765432.100000

float_format takes a %-style string or, in recent pandas versions, a callable. Note that 4.5e-05 is perfectly valid CSV and any parser reads it back correctly; only format the output if a human or a picky downstream tool needs it.

Plain Python: f-strings and format()

For individual values, the format specification mini-language gives full control. The f type is always fixed-point:

x = 0.000012345
big = 1.5e17
print(f"{x:f}")        # fixed point, 6 decimals by default
print(f"{x:.10f}")
print(f"{big:,.0f}")
print(f"{x:.10f}".rstrip("0").rstrip("."))
0.000012
0.0000123450
150,000,000,000,000,000
0.000012345

Avoid the g type if the goal is to avoid exponents: f"{x:g}" still gives 1.2345e-05.

Precision caveats

Printing more digits in fixed notation exposes the fact that floats are binary approximations:

print(f"{0.1:.20f}")
print(f"{1e23:f}")
print(f"{np.float32(0.1):.10f}")
0.10000000000000000555
99999999999999991611392.000000
0.1000000015

A float64 carries about 15–17 significant decimal digits; a float32 about 7. Digits beyond that are noise, not data. Scientific notation is often the more honest display for very large or very small measurements. If you need exact decimal values (money, accounting exports), store them as decimal.Decimal or as integer cents rather than formatting floats harder.

Common pitfalls

Summary

Scientific notation is a display choice, not a property of the data. Use np.set_printoptions(suppress=True, precision=...) or the np.printoptions context manager for NumPy arrays, pd.set_option("display.float_format", ...) or pd.option_context for pandas output, Styler.format for per-column report formatting, to_csv(float_format=...) and np.savetxt(fmt=...) for files, and f-strings with the f type for individual values. Keep in mind that extra digits beyond a float's precision carry no information.

Read next

More in Data