Menu

Time Series
Static
18 Python scripts generated for spiral plot this week

Spiral Plot

Chart overview

Spiral plots arrange time-series data along a spiral path, with each revolution representing a cycle (day, week, year).

Key points

  • This unique layout effectively reveals periodic patterns and seasonal trends while maintaining the continuous nature of time.
  • The form earns its place only when the period is known and fixed in advance: you set one revolution = one cycle, and a signal that repeats on that period lines up radially into a visible spoke, which is why spirals are good for spotting weekly seasonality in hourly data or annual seasonality in daily data.
  • Get the period wrong and the pattern smears into a meaningless coil, so a spiral is a confirmation tool, not a discovery tool - use an autocorrelation plot or periodogram first to find the period, then a spiral to show it.

Practical guidance

Perceptually it is demanding: radius conflates with time elapsed, arc length per unit time grows on outer loops, and readers cannot compare magnitudes across revolutions with any precision, so encode the value as color or marker size along the spiral rather than as radial distance, and keep the number of revolutions small. In matplotlib, map time to angle theta = 2*pi*(t mod period)/period and to a slowly growing radius on a polar axis. For most seasonal questions an ordinary line plot with the cycle on the x-axis, or a month-by-year heatmap, communicates faster; reach for the spiral when the continuous, unbroken nature of time is itself part of the story.

Create a Spiral Plot with your data using AI — no coding required.

Python Tutorial

How to create a spiral plot in Python

Use the full tutorial for implementation details, troubleshooting, and chart variations in matplotlib, seaborn, and plotly.

Python Scatter Plot Tutorial

Example Visualization

Spiral plot showing daily activity levels over a year

Create This Chart Now

Generate publication-ready spiral plots with AI in seconds. No coding required – just describe your data and let AI do the work.

View example prompt
Example AI Prompt

"Create a spiral plot showing 'Daily Step Count' over 2 years (730 days) to reveal seasonal activity patterns. Generate realistic fitness data with patterns: higher activity in spring/summer (8,000-12,000 steps), lower in winter (4,000-7,000 steps), weekly pattern (lower weekends), occasional zero days (sick days). Color points by step count using a YlOrRd gradient. Each spiral revolution = one year. Increase radius linearly from center (Year 1) outward (Year 2). Add concentric reference circles at 5,000 and 10,000 steps. Mark major holidays with annotations. Include a color legend and month labels around the outer edge. Title: 'Two-Year Activity Spiral - Daily Step Count'."

How to create this chart in 30 seconds

1

Upload Data

Drag & drop your Excel or CSV file. Plotivy securely processes it in your browser.

2

AI Generation

Our AI analyzes your data and generates the Spiral Plot code automatically.

3

Customize & Export

Tweak the design with natural language, then export as high-res PNG, SVG or PDF.

Newsletter

Get one weekly tip for better spiral plots

Join researchers receiving concise Python plotting techniques to improve chart clarity and reduce revision cycles.

No spam. Unsubscribe anytime.

Python Code Example

example.py
# === IMPORTS ===
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.patches import Circle
import matplotlib.dates as mdates
import random

# === USER-EDITABLE PARAMETERS ===
# Data generation parameters
start_date = '2022-01-01'  # Change: Start date of the spiral
end_date = '2023-12-31'    # Change: End date of the spiral
base_steps_winter = 5000    # Change: Base steps in winter (Dec-Feb)
base_steps_summer = 9000    # Change: Base steps in summer (Jun-Aug)
weekend_reduction = 0.7     # Change: Weekend step reduction factor (0.7 = 30% less)
sick_day_prob = 0.01        # Change: Probability of a zero-step sick day

# Visual parameters
figsize = (10, 10)          # Change: Figure size (width, height)
point_size = 30             # Change: Size of scatter points
line_width = 0.5            # Change: Width of connecting lines
month_label_size = 10       # Change: Font size for month labels
holiday_label_size = 9      # Change: Font size for holiday labels
reference_circle_alpha = 0.2  # Change: Opacity of reference circles
reference_circle_color = '#666666'  # Change: Color of reference circles

# Color parameters
colormap_name = 'YlOrRd'    # Change: Colormap for step counts (YlOrRd, viridis, plasma, etc.)
color_min = 4000            # Change: Minimum step count for color scaling
color_max = 12000           # Change: Maximum step count for color scaling

# More meaningful events to annotate (date, label)
events = [
    ('2022-04-15', 'Spring Break'),
    ('2022-09-01', 'Back to School'),
    ('2022-10-31', 'Halloween'),
    ('2023-04-15', 'Spring Break'),
    ('2023-09-01', 'Back to School'),
    ('2023-10-31', 'Halloween')
]

# === DATA GENERATION ===
date_range = pd.date_range(start=start_date, end=end_date, freq='D')
df = pd.DataFrame({'date': date_range})
df['day_of_year'] = df['date'].dt.dayofyear
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day_of_week'] = df['date'].dt.dayofweek  # Monday=0, Sunday=6
df['is_weekend'] = df['day_of_week'] >= 5

# Generate seasonal pattern
df['seasonal_factor'] = np.sin(2 * np.pi * (df['day_of_year'] - 80) / 365) * 0.4 + 1.0
df['base_steps'] = np.where(
    df['month'].isin([12, 1, 2]), base_steps_winter,
    np.where(df['month'].isin([6, 7, 8]), base_steps_summer,
             (base_steps_winter + base_steps_summer) / 2)
)

# Apply seasonal variation and weekly pattern
df['steps'] = df['base_steps'] * df['seasonal_factor']
df.loc[df['is_weekend'], 'steps'] = df.loc[df['is_weekend'], 'steps'] * weekend_reduction

# Add random variation and sick days
df['steps'] = df['steps'] * np.random.normal(1.0, 0.1, len(df))
df.loc[np.random.random(len(df)) < sick_day_prob, 'steps'] = 0
df['steps'] = np.round(df['steps']).astype(int)
df['steps'] = np.clip(df['steps'], 0, 15000)  # Cap at reasonable maximum

# === SPIRAL CALCULATION ===
# Convert dates to angles (0-2Ï€ per year)
df['angle'] = 2 * np.pi * (df['day_of_year'] - 1) / 365

# Radius increases linearly with year (0.5 for year 1, 1.0 for year 2)
df['radius'] = 0.5 + 0.5 * (df['year'] - df['year'].min())

# Convert polar to Cartesian coordinates
df['x'] = df['radius'] * np.cos(df['angle'])
df['y'] = df['radius'] * np.sin(df['angle'])

# === PLOT CREATION ===
fig, ax = plt.subplots(figsize=figsize, subplot_kw={'projection': 'polar'})

# Create colormap
cmap = plt.get_cmap(colormap_name)
norm = plt.Normalize(vmin=color_min, vmax=color_max)

# Plot the spiral with color mapping
scatter = ax.scatter(
    df['angle'], df['radius'], 
    c=df['steps'], 
    cmap=cmap, 
    norm=norm,
    s=point_size,
    alpha=0.8,
    edgecolors='none'
)

# Connect points with lines to form spiral
for year in df['year'].unique():
    year_df = df[df['year'] == year].sort_values('day_of_year')
    ax.plot(year_df['angle'], year_df['radius'], 
            color='#555555', 
            linewidth=line_width, 
            alpha=0.3)

# Add year circles
print("The solid circles represent each year in the visualization:")
for year in df['year'].unique():
    radius = 0.5 + 0.5 * (year - df['year'].min())
    circle = Circle((0, 0), radius, 
                    fill=False, 
                    linestyle='-', 
                    linewidth=1.5,
                    alpha=reference_circle_alpha,
                    color=reference_circle_color)
    ax.add_patch(circle)
    ax.text(0, radius, f'{year}', 
            ha='center', va='center',
            fontsize=10,
            color=reference_circle_color,
            bbox=dict(boxstyle='round', facecolor='white', alpha=0.7))

# Add month labels around the outer edge
month_angles = {1: 0, 2: np.pi/6, 3: np.pi/3, 4: np.pi/2, 
                5: 2*np.pi/3, 6: 5*np.pi/6, 7: np.pi,
                8: 7*np.pi/6, 9: 4*np.pi/3, 10: 3*np.pi/2,
                11: 5*np.pi/3, 12: 11*np.pi/6}
month_names = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

for month, angle in month_angles.items():
    ax.text(angle, 1.15, month_names[month-1],
            ha='center', va='center',
            fontsize=month_label_size,
            bbox=dict(boxstyle='round', facecolor='white', alpha=0.7))

# Add event annotations (spaced to avoid overlap)
for date, label in events:
    event_row = df[df['date'] == date].iloc[0]
    ax.annotate(label,
                xy=(event_row['angle'], event_row['radius']),
                xytext=(10, 10),
                textcoords='offset points',
                fontsize=holiday_label_size,
                arrowprops=dict(arrowstyle='->', color='#333333'),
                bbox=dict(boxstyle='round', pad=0.2, facecolor='white', alpha=0.7))

# Customize plot appearance
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylim(0, 1.2)
ax.spines['polar'].set_visible(False)

# Add horizontal colorbar below the graph with reduced padding
cbar = plt.colorbar(scatter, ax=ax, orientation='horizontal', pad=0.05)
cbar.set_label('Daily Step Count', labelpad=10)

# Add title
plt.title('Two-Year Activity Spiral - Daily Step Count', 
          pad=20, fontsize=14, fontweight='bold')

plt.tight_layout()
plt.show()
# END-OF-CODE

Opens the Analyze page with this code pre-loaded and ready to execute

Console Output

Output
730 days plotted across 2.0 spiral turns
Mean daily steps: 7987

Common Use Cases

  • 1Seasonal pattern detection
  • 2Cyclical trend analysis
  • 3Activity tracking over time
  • 4Weather pattern visualization

Pro Tips

Choose spiral period to match data cycle

Use color to encode values

Add radial reference lines

Frequently asked questions

When should you use a spiral plot?

Spiral plots arrange time-series data along a spiral path, with each revolution representing a cycle (day, week, year). This unique layout effectively reveals periodic patterns and seasonal trends while maintaining the continuous nature of time. Common applications include seasonal pattern detection, cyclical trend analysis, and activity tracking over time.

Which Python libraries can create a spiral plot?

A spiral plot can be built in Python with matplotlib — matplotlib for precise control over axes, annotations, and journal styling. In Plotivy you describe the figure and it writes the matplotlib code for you.

Can I make a spiral plot without writing Python code?

Yes. Describe the spiral plot you need in plain language and upload your dataset — Plotivy's AI writes the Python code and renders a publication-ready figure. You still get the full, editable matplotlib source, so nothing is locked in a black box.

What are best practices for a clear spiral plot?

Choose spiral period to match data cycle. Use color to encode values.

Long-tail keyword opportunities

how to create spiral plot in python
spiral plot matplotlib
spiral plot seaborn
spiral plot plotly
spiral plot scientific visualization
spiral plot publication figure python

High-intent chart variations

Spiral Plot with confidence interval overlays
Spiral Plot optimized for publication layouts
Spiral Plot with category-specific color encoding
Interactive Spiral Plot for exploratory analysis

Library comparison for this chart

matplotlib

Best when you need full control over axis formatting, annotation placement, and journal-specific styling for spiral-plot.

Free Cheat Sheet

Scientific Chart Selection Cheat Sheet

Not sure whether to use a Violin Plot, Box Plot, or Ridge Plot? Download our single-page reference mapping the most-used scientific chart types, exactly when to use them, and the core Matplotlib/Seaborn functions.

Comparison Charts
Distribution Charts
Time Series Data
Common Mistakes
No spam. Unsubscribe anytime.