配色

可以在平时阅读时保存一些好看图像的配色/架构,例如

image.png|400

image.png|475

或者可以直接参考 配色网站,不过比较麻烦的是得自己去找颜色

绘图

AI 辅助

用提示词生成绘图脚本,例如仙人掌图(cactus)的代码如下:

import pandas as pd
import matplotlib.pyplot as plt
import os
import numpy as np
 
# --- 配置参数 ---
# CSV文件所在的目录
# EXPR_NAME = "MagicSquare-LS"
EXPR_NAME = "SAT22"
 
DATA_DIR = f"./data/{EXPR_NAME}"
# 预设的超时时间限制(秒)。所有超过此时间的,都视为超时。
TIMEOUT = 5000
# 输出图片的文件名
OUTPUT_FILENAME = f"fig/{EXPR_NAME}_cactus_plot.png"
 
BACKGOUND = "gray"
# , #, #, #
# 算法名称及其对应的绘图样式(用于确保学术严谨性,避免花哨)
# 使用不同的标记、线条样式和有限的颜色
ALGORITHM_STYLES = {
    "CardSAT-INC": {
        "label": "CardSAT-INC",
        "color": "#85C3DC",
        "marker": "o",
        "linestyle": "-",
    },
    "YalSAT": {
        "label": "YalSAT",
        "color": "#8DAFAB",
        "marker": "^",
        "linestyle": "--",
    },
    "CCAnr": {
        "label": "CCAnr",
        "color": "#E2C098",
        "marker": "s",
        "linestyle": ":",
    },
    "NuPBO": {
        "label": "NuPBO",
        "color": "#DAC6CF",
        "marker": "x",
        "linestyle": "-",
    },
}
 
 
def load_and_prepare_data(data_dir, timeout, styles):
    """
    加载所有 CSV 文件,处理数据,并为仙人掌图准备排序后的求解时间。
    """
    algorithm_data = {}
 
    # 遍历指定目录下的所有文件
    for filename in os.listdir(data_dir):
        if filename.endswith(".csv"):
            # 从文件名中提取算法名称(假设文件名格式为 'AlgorithmName.csv')
            algorithm_name = filename.replace("-results.csv", "")
 
            if algorithm_name not in styles:
                print(
                    f"Warning: Skipping file {filename}. No style defined for '{algorithm_name}'."
                )
                continue
 
            filepath = os.path.join(data_dir, filename)
 
            try:
                # 1. 读取 CSV 文件
                df = pd.read_csv(filepath)
 
                # 2. 数据清洗与处理:将超时或未解决的实例时间设为 TIMEOUT
                # 假设 'time' 列记录了时间,'status' 列记录了状态
 
                # a) 处理超时时间
                df["processed_time"] = np.where(
                    df["time"] >= timeout, timeout, df["time"]
                )
 
                # b) 进一步处理未解决的状态(如果状态不是 'solved',也视为超时)
                # 您可能需要根据您的实际状态标签修改这里的条件
                if "result" in df.columns:
                    df["processed_time"] = np.where(
                        df["result"] == "TIMEOUT",
                        timeout,
                        df["processed_time"],
                    )
 
                # 3. 核心步骤:按时间升序排序
                # 仙人掌图的 X 轴是解决的问题数量,Y 轴是求解时间
                solved_df = df[
                    (df["time"] <= timeout) & (df["result"] != "TIMEOUT")
                ].copy()
                sorted_times = solved_df["time"].sort_values().tolist()
 
                # 4. Y轴数据准备:累积求解时间
                # 仙人掌图的 Y 轴是 *求解时间*,X 轴是 *解决的问题数*
                # 注意:这里我们实际使用的Y轴是排序后的时间本身,而不是累积时间,
                # 因为仙人掌图是 (已解决问题数, 求解该问题所需时间) 的曲线
 
                algorithm_data[algorithm_name] = sorted_times
 
            except Exception as e:
                print(f"Error processing file {filename}: {e}")
                continue
 
    return algorithm_data
 
 
def plot_cactus_plot(data, styles, timeout, output_filename):
    """
    绘制仙人掌图。
    """
    plt.style.use("default")  # 使用默认或尝试 'seaborn-v0_8-whitegrid' 或 ''
 
    fig, ax = plt.subplots(figsize=(10, 6))
 
    fig.patch.set_facecolor("#f5f5f5")
    # ax.set_facecolor("#e8e8e8")
 
    all_num_problems = []
 
    # 绘制每个算法的曲线
    for algo_name, times in data.items():
        style = styles[algo_name]
 
        # X 轴数据:已解决问题的数量(从 1 开始)
        # 如果算法解决了 N 个问题,那么 X 轴的坐标就是 1, 2, 3, ..., N
        num_solved = len(times)
        x_data = np.arange(1, num_solved + 1)
        y_data = np.array(times)
 
        # 记录所有算法的总问题数,用于确定 X 轴范围
        all_num_problems.append(num_solved)
 
        # 绘制曲线,使用预定义的学术样式
        ax.plot(
            x_data,
            y_data,
            label=style["label"],
            color=style["color"],
            marker=style.get("marker", None),
            linestyle=style.get("linestyle", "-"),
            linewidth=2,
            markevery=max(1, num_solved // 15),  # 每隔一定数量的点才显示标记,避免拥挤
            markersize=5,
        )
 
    # --- 图表美化设置 (学术严谨性) ---
 
    # 设置 X 轴(已解决的问题实例数量)
    max_problems = max(all_num_problems) if all_num_problems else 1
    ax.set_xlabel("Number of Solved Instances", fontsize=12)
    ax.set_xlim(0, max_problems * 1.05)
    # 确保 X 轴刻度是整数
    ax.xaxis.set_major_locator(plt.MaxNLocator(integer=True))
 
    # 设置 Y 轴(求解时间)
    ax.set_ylabel("CPU Time (seconds)", fontsize=12)
    # 设置 Y 轴的上限为 TIMEOUT,并使用对数刻度以清晰显示小时间差异
    ax.set_ylim(bottom=0.01, top=timeout * 1.1)
    ax.set_yscale("log")
 
    # --- 关键修改:超时线不设置 label,因此不会进入图例 ---
    ax.axhline(y=timeout, color="red", linestyle="--", linewidth=1, zorder=0)
 
    # 可以在图内添加文本标记超时线,以提高清晰度
    # ax.text(
    #     ax.get_xlim()[1] * 0.98,
    #     timeout * 1.05,
    #     f"Timeout ({timeout}s)",
    #     color="red",
    #     fontsize=10,
    #     ha="right",
    #     va="center",
    # )
 
    # 添加网格线,帮助阅读数据点
    # ax.grid(True, which="both", linestyle="-", linewidth=0.5, alpha=0.7)
 
    # 添加图例
    # 使用 loc='best' 或指定位置,frameon=True 增强可读性
    ax.legend(loc="lower right", fontsize=10, frameon=True, shadow=False)
 
    # 标题(可选,通常在论文中放在图下方)
    # plt.title('Cactus Plot: Comparison of Algorithm Performance', fontsize=14)
 
    # 调整布局,保存图像
    plt.tight_layout()
    plt.savefig(output_filename, dpi=300)
    plt.close(fig)
    print(f"Cactus Plot successfully saved to {output_filename}")
 
 
# --- 主执行流程 ---
 
# 1. 检查数据目录是否存在
if not os.path.exists(DATA_DIR):
    print(f"Error: Data directory '{DATA_DIR}' not found.")
    print("Please create the directory and place your CSV files inside.")
else:
    # 2. 加载和准备数据
    performance_data = load_and_prepare_data(DATA_DIR, TIMEOUT, ALGORITHM_STYLES)
 
    if performance_data:
        # 3. 绘制仙人掌图
        plot_cactus_plot(performance_data, ALGORITHM_STYLES, TIMEOUT, OUTPUT_FILENAME)
    else:
        print(
            "No valid data loaded for plotting. Check your CSV files and ALGORITHM_STYLES."
        )

提示词需要传递的信息主要是:

  1. 配色,字体
  2. csv 文件格式
  3. 以及你自己的一些想法

AI 生成

nano banana 来生成,具体流程为:

  1. 用提示词在简单模型上生成绘图提示词,例如在 deepseek 上用以下提示词:

    你是一名经验丰富的科研绘图设计师,请仔细阅读我提供的文献信息,充分理解研究内容,并结合我提供的参考图(模仿该图的配色、设计风格等),生成可用于科研发表的配图的英文提示词。

  2. 用生成的提示词,复制粘贴到 Nano Banana 中生成

Matplotlib 的 Marker

image.png

或者可以考虑使用 unicode 字符编码,例如 "$\u266B$"(支持 STIX Font Math 中的字符)

Tip

如果需要空心的话,注明 color="" 以及 edgecolors="#hex" 即可(边框有颜色,中间无颜色)