栞忘れてください
FROM THE NOTEBOOK

科研绘图工具

6 min read

配色#

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

image.png

image.png

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

绘图#

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 中的字符)

CONVERSATION

讨论

想法、补充,或只是打个招呼。

← 返回文章
关系图谱 ↓

全局关系图谱

页面标签
笔记
↑ ↓ 选择↵ 打开Esc 关闭