Pandas to_string(): Readable Text Tables and Reports

Use to_string() to create readable table text. Choose displayed columns, headers, missing markers and numeric precision, then write a clearly scoped report.

Watch: DataFrame text output with to_string()

Create a DataFrame and return its text 🔝

to_string() produces console-friendly table text, not CSV, JSON or Python source. Without buf it returns a string. Use print() to show its line breaks.

import pandas as pd
from io import StringIO, BytesIO
import sqlite3

df = pd.DataFrame({"NAME": ["Ravi", "Raju", "Alex"], "ID": [1, 2, 3],
    "MATH": [30, 40, 50], "ENGLISH": [20, 30, 40]})
text = df.to_string()
print(text)
print("Return type:", type(text).__name__)
assert isinstance(text, str)

Expected output

   NAME  ID  MATH  ENGLISH
0  Ravi   1    30       20
1  Raju   2    40       30
2  Alex   3    50       40
Return type: str

Write text to a file or buffer 🔝

Passing buf writes the table and returns None. The buffer demonstration avoids creating a file during Run All. Uncomment the file call in Colab to save a UTF-8 report. Windows paths can use a raw string such as r"D:\my_data\my_file.txt".

buffer = StringIO()
returned = df.to_string(buf=buffer, index=False)
print(buffer.getvalue())
print("Return value:", returned)
assert returned is None
assert buffer.getvalue() == df.to_string(index=False)
# Optional file output:
# df.to_string(buf="student_report.txt", index=False, encoding="utf-8")

Expected output

NAME  ID  MATH  ENGLISH
Ravi   1    30       20
Raju   2    40       30
Alex   3    50       40
Return value: None

Choose columns and hide the index 🔝

columns controls displayed fields; index=False hides row labels. These formatting choices do not change the source table.

print(df.to_string(columns=["NAME", "ID"], index=False))
assert df.columns.tolist() == ["NAME", "ID", "MATH", "ENGLISH"]

Expected output

NAME  ID
Ravi   1
Raju   2
Alex   3

header=False hides column headings. A header alias list must match the displayed columns. The original column labels remain unchanged.

print("Aliases:")
print(df.to_string(header=["NAME1", "ID2", "MATH3", "ENGLISH4"]))
print("No header:")
print(df.to_string(header=False, index=False))
assert df.columns[0] == "NAME"

Expected output

Aliases:
  NAME1 ID2 MATH3 ENGLISH4
0  Ravi   1    30       20
1  Raju   2    40       30
2  Alex   3    50       40
No header:
Ravi 1 30 20
Raju 2 40 30
Alex 3 50 40

Set minimum column widths and header alignment 🔝

col_space controls minimum column width, not a strict maximum. justify affects header alignment; actual value alignment also depends on dtype. A long value can still make a column wide.

print(df.to_string(col_space=10, index=False))
print("Centered headers:")
print(df.to_string(justify="center", index=False))

Expected output

      NAME         ID       MATH    ENGLISH
      Ravi          1         30         20
      Raju          2         40         30
      Alex          3         50         40
Centered headers:
NAME  ID  MATH  ENGLISH
Ravi  1    30     20   
Raju  2    40     30   
Alex  3    50     40

Format missing values without replacing them 🔝

na_rep changes the displayed missing marker. The stored missing values remain missing. See the Data Cleaning hub for value treatment rather than display formatting.

measurements = pd.DataFrame({"product": ["Pen", "Book", "Bag"], "amount": [5.25, None, 30.0]})
print(measurements.to_string(index=False, na_rep="Missing"))
assert measurements["amount"].isna().sum() == 1

Expected output

product  amount
    Pen    5.25
   Book Missing
    Bag   30.00

Format numeric values for a report 🔝

float_format applies to floating-point values; per-column formatters provide more specific formatting. Rounded display does not round the stored values. Choose precision appropriate to the report.

print(measurements.to_string(index=False, na_rep="Missing", float_format=lambda value: f"{value:.2f}"))
print(df.to_string(index=False, formatters={"ID": lambda value: f"S{value:03d}"}))
assert measurements.loc[0, "amount"] == 5.25
assert df["ID"].tolist() == [1, 2, 3]

Expected output

product  amount
    Pen    5.25
   Book Missing
    Bag   30.00
NAME   ID  MATH  ENGLISH
Ravi S001    30       20
Raju S002    40       30
Alex S003    50       40

Limit displayed rows and columns 🔝

max_rows, max_cols and max_colwidth limit the representation, not the dataset. Ellipses mean the display is incomplete. Use a deliberately selected preview for large tables and retain full-table totals separately.

wide = pd.DataFrame({"id": range(1, 9), "description": ["Long product description"] * 8,
    "amount": range(10, 18), "status": ["paid"] * 8})
print(wide.to_string(index=False, max_rows=4, max_cols=3, max_colwidth=12, show_dimensions=True))
assert wide.shape == (8, 4)

Expected output

 id  ... status
  1  ...   paid
  2  ...   paid
 ..  ...    ...
  7  ...   paid
  8  ...   paid

[8 rows x 4 columns]

Read CSV data before formatting 🔝

StringIO makes this import runnable without an uploaded file. For your CSV, supply its path or URL. to_string() works on the resulting DataFrame regardless of its source. See read_csv().

csv_text = df.to_csv(index=False)
imported = pd.read_csv(StringIO(csv_text))
print(imported.to_string(index=False))
assert imported.equals(df)

Expected output

NAME  ID  MATH  ENGLISH
Ravi   1    30       20
Raju   2    40       30
Alex   3    50       40

Read Excel data before formatting 🔝

This in-memory workbook uses read_excel(). Excel needs an engine such as openpyxl; the notebook can continue if it is unavailable. Replace the buffer with your workbook path for your own data.

try:
    import openpyxl
except ImportError:
    print("Excel example requires openpyxl; continue with other sources.")
else:
    workbook = BytesIO()
    df.to_excel(workbook, index=False, engine="openpyxl")
    workbook.seek(0)
    imported = pd.read_excel(workbook, engine="openpyxl")
    print(imported.to_string(index=False))
    assert imported.shape == df.shape

Expected output

NAME  ID  MATH  ENGLISH
Ravi   1    30       20
Raju   2    40       30
Alex   3    50       40

Read a database result and format it 🔝

SQLite provides a self-contained database example. For MySQL, use an existing authorized SQLAlchemy connection and keep credentials out of the tutorial or shared notebook. The formatting step is the same.

with sqlite3.connect(":memory:") as connection:
    df.to_sql("student", connection, index=False)
    imported = pd.read_sql_query("SELECT NAME, ID, MATH, ENGLISH FROM student ORDER BY ID LIMIT 10", connection)
print(imported.to_string(index=False))
assert imported.shape == (3, 4)
# Optional MySQL adaptation using your configured SQLAlchemy engine:
# with engine.connect() as connection:
#     imported = pd.read_sql_query("SELECT * FROM student ORDER BY id LIMIT 10", connection)
# print(imported.to_string(index=False))

Expected output

NAME  ID  MATH  ENGLISH
Ravi   1    30       20
Raju   2    40       30
Alex   3    50       40

Practical example: combine totals and a preview 🔝

This synthetic sales report includes the population behind its total. A two-row preview is labelled as a preview, not presented as the whole dataset. Use head() and sum() for the two different tasks.

sales = pd.DataFrame({"order_id": [101, 102, 103, 104],
    "product": ["Pen", "Book", "Bag", "Pencil"], "amount": [5.25, 20.0, 30.0, 8.5]})
preview = sales.head(2)
report = f"Sales report: {len(sales)} orders; revenue {sales['amount'].sum():.2f}\n"
report += f"Preview: first {len(preview)} orders\n"
report += preview.to_string(index=False, float_format=lambda value: f"{value:.2f}")
print(report)
assert sales["amount"].sum() == 63.75
assert len(preview) == 2

Expected output

Sales report: 4 orders; revenue 63.75
Preview: first 2 orders
 order_id product  amount
      101     Pen    5.25
      102    Book   20.00

Use CSV for structured interchange 🔝

to_string() is designed for people reading a table. Do not parse its aligned whitespace as a reliable interchange format. Use to_csv(), to_json() or to_excel() when another program needs structured records.

csv_output = sales.to_csv(index=False)
loaded = pd.read_csv(StringIO(csv_output))
print(csv_output.rstrip())
print("Same values:", loaded.equals(sales))
assert loaded.equals(sales)
# Optional report file:
# from pathlib import Path
# Path("sales_preview.txt").write_text(report, encoding="utf-8")

Expected output

order_id,product,amount

101,Pen,5.25

102,Book,20.0

103,Bag,30.0

104,Pencil,8.5
Same values: True

Common questions 🔝

Why are backslash-n characters visible? A string representation may escape line breaks; print the string. Does hiding the index remove it? No; this changes display only. Does float_format change stored amounts? No. Can this create a UTF-8 file? Yes; use a file buffer or write the returned text with an explicit encoding. Does truncation reduce memory used by the source? No. Should I print a whole large table? Select a bounded preview and calculate full-table measures separately. Continue with read_json(), list conversion and the student SQL sample.

Exercise: format a three-column preview 🔝

Show the first three sales orders with order_id, product and amount, without the index and with amounts displayed to two decimal places. Confirm that the full sales table still has four rows.

Exercise solution 🔝

The display selection affects only the report text.

answer = sales.head(3).to_string(columns=["order_id", "product", "amount"],
    index=False, float_format=lambda value: f"{value:.2f}")
print(answer)
assert "5.25" in answer
assert len(sales) == 4

Expected output

 order_id product  amount
      101     Pen    5.25
      102    Book   20.00
      103     Bag   30.00

Practice in Google Colab 🔝

Open in Google Colab View on GitHub
Run the examples in order, change displayed columns and formatting options, then compare text with the stored values. Save your own copy to keep edits. All sample tables are included in the notebook.

Reference: Pandas DataFrame.to_string documentation.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer