基于条件为Matplotlib绘图中单调增减数据点交替着色的技术咨询
Hey there! Let's work through this problem together. I’ll walk you through a step-by-step solution to plot your cyclic cumulative data with the exact color rules you need, using pandas and matplotlib.
Step 1: Prepare Sample Data (or Use Your Own)
First, let’s create a sample dataset that mimics your scenario—cumulative values that reset to 0 after hitting a threshold Y, with some non-strict periodicity. If you already have your DataFrame, skip this part and use your own df['X'] column.
import pandas as pd import matplotlib.pyplot as plt import numpy as np # Simulate cyclic cumulative data (adjust Y and cycles to match your data) np.random.seed(42) cycles = 3 Y = 100 # Threshold where resets happen data = [] current_value = 0 # Generate multiple cycles of increment -> reset for _ in range(cycles): # Add noisy increments to simulate non-strict periodicity increments = np.random.randint(5, 15, size=10) for inc in increments: current_value += inc if current_value >= Y: data.append(current_value) current_value = 0 data.append(current_value) break data.append(current_value) # Add a final partial increment cycle final_increments = np.random.randint(5, 15, size=5) for inc in final_increments: current_value += inc data.append(current_value) # Create DataFrame df = pd.DataFrame({"X": data})
Step 2: Calculate Trends and Reset Cycles
We need to identify three things:
- Whether each point is an increment or decrement relative to the previous point
- When a reset (large decrement from Y to 0) occurs
- How many resets have happened to distinguish the first increment from later ones
# Calculate the difference between each point and the previous one df["diff"] = df["X"].diff() # Mark reset points (where the value drops, i.e., diff is negative) df["is_reset"] = df["diff"] < 0 # Count cumulative resets to split the data into "first cycle" and "subsequent cycles" df["reset_count"] = df["is_reset"].cumsum()
Step 3: Assign Colors Based on Your Rules
Now we’ll map each data point to the correct color using a custom function:
- Color A: First cycle increments (reset_count = 0 and diff > 0)
- Color B: All decrements (diff < 0)
- Color C: Subsequent cycle increments (reset_count ≥ 1 and diff > 0)
- The first point (NaN diff) gets Color A since it’s the start of the first increment.
def assign_color(row): if pd.isna(row["diff"]): # First point belongs to the first increment cycle return "red" # Replace with your actual Color A if row["diff"] > 0: if row["reset_count"] == 0: return "red" # Color A else: return "green" # Color C else: return "blue" # Color B (all decrements) df["color"] = df.apply(assign_color, axis=1)
Step 4: Plot the Data with Matplotlib
Finally, we’ll plot the points using their assigned colors. We’ll use scatter plots for clarity, but you can adapt this to line plots if needed.
plt.figure(figsize=(10, 6)) # Plot each data point with its assigned color plt.scatter(df.index, df["X"], color=df["color"], s=50, alpha=0.8) # Add labels, title, and legend plt.title("Cyclic Cumulative Data with Trend-Based Coloring") plt.xlabel("Data Point Index") plt.ylabel("Cumulative Value (X)") # Create custom legend handles legend_handles = [ plt.Line2D([], [], marker="o", color="red", linestyle="", markersize=10, label="First Increment (Color A)"), plt.Line2D([], [], marker="o", color="blue", linestyle="", markersize=10, label="Decrement (Color B)"), plt.Line2D([], [], marker="o", color="green", linestyle="", markersize=10, label="Subsequent Increments (Color C)") ] plt.legend(handles=legend_handles) plt.grid(True, alpha=0.3) plt.show()
Key Notes
- Replace the placeholder colors (
red,blue,green) with your actual Color A/B/C values (e.g., hex codes like#FF5733). - If you prefer line plots instead of scatter points, group the DataFrame by color and plot each group separately (you can add a loop over
df.groupby('color')to achieve this). - This approach handles non-strict periodicity (e.g., varying increment sizes) since it relies on actual value changes, not fixed cycle lengths.
内容的提问来源于stack exchange,提问作者Alexis Moreno

