2026, Jan 09 03:00

How to Show X-Axis Labels and Ticks in NetworkX + Matplotlib Timeline Graphs (hide_ticks=False)

X-axis labels and ticks missing in NetworkX Matplotlib timeline graphs? Learn why draw_networkx_* hides them by default and fix with hide_ticks=False.

When plotting a timeline-like network with NetworkX and Matplotlib, a surprisingly common issue is that the X-axis label and ticks don’t show up, even though the axis is configured as dates and the label is explicitly set. The plot renders nodes and edges just fine, but the axis area looks empty. Here is why that happens and how to fix it cleanly.

Reproducing the issue

The following minimal script builds a directed graph from a time-ordered DataFrame, positions nodes by timestamp on the X-axis, and formats the axis as dates. Everything looks correct except the missing X-axis label and ticks.

import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.dates import date2num, AutoDateLocator, AutoDateFormatter
from datetime import datetime, timedelta
# Create time-ordered data
n_rows = 10
base_dt = datetime(2025, 10, 1, 8, 0)
payload = {
    "From_dt": [base_dt + timedelta(hours=4 * j) for j in range(n_rows)],
    "Description": [f"Entry {j}" for j in range(n_rows)],
    "Category": ["100 Advance" if j % 2 == 0 else "Other" for j in range(n_rows)],
}
frame = pd.DataFrame(payload)
# Build directed graph
net_digraph = nx.DiGraph()
for idx, rec in frame.iterrows():
    net_digraph.add_node(
        idx,
        timestamp=rec["From_dt"],
        text=rec["Description"],
        category=rec["Category"],
    )
    if idx > 0:
        net_digraph.add_edge(idx - 1, idx, type="time")
# Position nodes by datetime on X, index on Y
coord_map = {i: (date2num(frame.loc[i, "From_dt"]), -i) for i in frame.index}
# Plot canvas
canvas, axes = plt.subplots(figsize=(12, 6))
# Anchor invisible line so Matplotlib treats X-axis as dates
axes.plot(date2num(frame["From_dt"]), [-k for k in frame.index], alpha=0)
# Draw graph
nx.draw_networkx_edges(net_digraph, coord_map, ax=axes, edge_color="gray", arrows=True)
color_vec = [
    "green" if net_digraph.nodes[i]["category"] == "100 Advance" else "orange"
    for i in net_digraph.nodes
]
nx.draw_networkx_nodes(net_digraph, coord_map, ax=axes, node_color=color_vec, node_size=100)
# Sparse labels to reduce clutter
stride = max(1, len(frame) // 5)
tagmap = {i: frame.loc[i, "Category"] for i in range(0, len(frame), stride)}
nx.draw_networkx_labels(net_digraph, coord_map, tagmap, font_size=9, ax=axes)
# Axis labels and grid
axes.set_xlabel("Date and Time")
axes.set_ylabel("Entry Index")
axes.set_title("Minimal Timeline Graph with Date X-Axis")
axes.grid(True)
# Date formatting
axes.xaxis_date()
tick_locator = AutoDateLocator()
tick_formatter = AutoDateFormatter(tick_locator)
axes.xaxis.set_major_locator(tick_locator)
axes.xaxis.set_major_formatter(tick_formatter)
# Layout for rotated ticks
plt.subplots_adjust(bottom=0.3)
canvas.autofmt_xdate(rotation=45)
# Interactive coordinate hint
def coord_fmt(x, y):
    try:
        return f"x = {mdates.num2date(x).strftime('%d-%b %H:%M')}, y = {y:.1f}"
    except Exception:
        return f"x = {x:.2f}, y = {y:.1f}"
axes.format_coord = coord_fmt
plt.show()

What is happening

NetworkX’s high-level drawing helpers, such as draw_networkx_edges, draw_networkx_nodes, and draw_networkx_labels, hide the axis decorations by default. That behavior includes ticks and their labels, and it also suppresses axis labels. The X-axis is still correctly configured as dates, but you won’t see any of it until you explicitly allow ticks to be shown.

It’s not a Matplotlib date formatting issue, nor is it related to the invisible “anchor” line; the graph drawing calls are simply turning the axis decorations off unless you tell them otherwise.

The fix

Pass hide_ticks=False to each draw_networkx_XXX call. This keeps the graph rendering intact while preserving the axis ticks and labels, including the X-axis label you set.

import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.dates import date2num, AutoDateLocator, AutoDateFormatter
from datetime import datetime, timedelta
# Create time-ordered data
n_rows = 10
base_dt = datetime(2025, 10, 1, 8, 0)
payload = {
    "From_dt": [base_dt + timedelta(hours=4 * j) for j in range(n_rows)],
    "Description": [f"Entry {j}" for j in range(n_rows)],
    "Category": ["100 Advance" if j % 2 == 0 else "Other" for j in range(n_rows)],
}
frame = pd.DataFrame(payload)
# Build directed graph
net_digraph = nx.DiGraph()
for idx, rec in frame.iterrows():
    net_digraph.add_node(
        idx,
        timestamp=rec["From_dt"],
        text=rec["Description"],
        category=rec["Category"],
    )
    if idx > 0:
        net_digraph.add_edge(idx - 1, idx, type="time")
# Position nodes by datetime on X, index on Y
coord_map = {i: (date2num(frame.loc[i, "From_dt"]), -i) for i in frame.index}
# Plot canvas
canvas, axes = plt.subplots(figsize=(12, 6))
# Anchor invisible line so Matplotlib treats X-axis as dates
axes.plot(date2num(frame["From_dt"]), [-k for k in frame.index], alpha=0)
# Draw graph with ticks enabled
nx.draw_networkx_edges(
    net_digraph, coord_map, ax=axes, edge_color="gray", arrows=True, hide_ticks=False
)
color_vec = [
    "green" if net_digraph.nodes[i]["category"] == "100 Advance" else "orange"
    for i in net_digraph.nodes
]
nx.draw_networkx_nodes(
    net_digraph, coord_map, ax=axes, node_color=color_vec, node_size=100, hide_ticks=False
)
# Sparse labels to reduce clutter
stride = max(1, len(frame) // 5)
tagmap = {i: frame.loc[i, "Category"] for i in range(0, len(frame), stride)}
nx.draw_networkx_labels(
    net_digraph, coord_map, tagmap, font_size=9, ax=axes, hide_ticks=False
)
# Axis labels and grid
axes.set_xlabel("Date and Time")
axes.set_ylabel("Entry Index")
axes.set_title("Minimal Timeline Graph with Date X-Axis")
axes.grid(True)
# Date formatting
axes.xaxis_date()
tick_locator = AutoDateLocator()
tick_formatter = AutoDateFormatter(tick_locator)
axes.xaxis.set_major_locator(tick_locator)
axes.xaxis.set_major_formatter(tick_formatter)
# Layout for rotated ticks
plt.subplots_adjust(bottom=0.3)
canvas.autofmt_xdate(rotation=45)
# Interactive coordinate hint
def coord_fmt(x, y):
    try:
        return f"x = {mdates.num2date(x).strftime('%d-%b %H:%M')}, y = {y:.1f}"
    except Exception:
        return f"x = {x:.2f}, y = {y:.1f}"
axes.format_coord = coord_fmt
plt.show()

Why it matters

If you are building timeline visualizations, GraphRAG-style plots, or any time-indexed network views, the axis can carry crucial context. Dates, tick spacing, and rotated labels often make the difference between a readable diagnostic chart and an opaque picture. Knowing that draw_networkx_* hides ticks and labels by default prevents wasted time chasing date formatters, locators, and other unrelated parts of the stack.

Takeaways

When using NetworkX drawing helpers with Matplotlib, remember that ticks and axis labels are hidden by default. Enable them by passing hide_ticks=False to each draw_networkx_XXX call in the same figure. Keep your imports organized at the top and keep the plotting logic in a single contiguous block so axis configuration and rendering stay predictable.