0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

gnuplotを用いたライブラリをC言語で作ってみた.

Last updated at Posted at 2024-11-12

ファイルからグラフを作成するライブラリ

最近数値計算をするプログラムをC言語で書く機会が多いので,
その処理をライブラリにして再利用できるようにしておこうと思ったのがきっかけ.

機能

誤差計算

calculate.c
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include "calculate.h"

void calcurlate_error(const char *file, const char *file1, const char *file2){
    FILE *fp = fopen(file,"w");
    FILE *fp1 = fopen(file1,"r");
    FILE *fp2 = fopen(file2,"r");
    
    if(fp1 == NULL || fp2 == NULL){
        printf("file null error");
        return;
    }

    double x1,x2,y1,y2;
    double error;
    while(fscanf(fp1,"%lf,%lf",&x1,&y1) == 2 && fscanf(fp2,"%lf,%lf",&x2,&y2) == 2){
        if(fabs(x1 - x2) > 1e-6){
            printf("xの値が一致しません");
            break;
        }
        error = fabs(y1 - y2);
        printf("%8.3lf,%8.5lf\n",x1,error);
        fprintf(fp,"%8.3lf,%8.5lf\n",x1,error);
    }
    
    fclose(fp);
    fclose(fp1);
    fclose(fp2);
}

2つのファイルのデータを使って誤差を求めます.
image.png
image.png

上記のようなデータを2つ用意して2列目の値を比較します.
使用例としては理論値と計算データを比較するときに用います.

1つのファイルのグラフを作成

calculate.c
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include "calculate.h"

int aFilePlotter(const char *file){
    FILE *gp;
    gp = popen("gnuplot -persist","w");
    fprintf(gp,"set multiplot\n");
    fprintf(gp,"set datafile separator ','");
    //fprintf(gp,"set xrange[0:2]\n");
    //fprintf(gp,"set yrange[0:0.6]\n");
    //fprintf(gp,"set xlabel 't'\n");
    //fprintf(gp,"set ylabel 'y(t)'\n");
    fprintf(gp,"plot '%s' with line\n",file);
    fprintf(gp,"quit\n");
    pclose(gp);
    
    return 0;
}

1つファイルを引数として渡すとグラフを作成してくれます.

複数のファイルのグラフを作成

calculate.c
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include "calculate.h"

int multiFilePlotter(int numFiles, ...)
{
    FILE *gp;
    gp = popen("gnuplot -persist","w");
    if(gp == NULL){
        fprintf(stderr, "Error: Could not open gnuplot\n");
        return -1;
    }

    fprintf(gp,"set multiplot\n");
    fprintf(gp,"set datafile separator ','");
    //fprintf(gp,"set xrange[0:2]\n");
    //fprintf(gp,"set yrange[0:0.6]\n");
    fprintf(gp,"set xlabel 't'\n");
    fprintf(gp,"set ylabel 'y(t)'\n");
    va_list args;
    va_start(args, numFiles);
    fprintf(gp, "plot ");
    for(int i = 0; i < numFiles; i++){
       const char *file = va_arg(args, const char*);
       fprintf(gp, "'%s' with lines", file);
       if(i < numFiles - 1){
        fprintf(gp, ", ");
       }
    }
    fprintf(gp,"\n"); 
    va_end(args);
    fprintf(gp,"quit\n");
    pclose(gp);

    return 0;
}

複数のファイルを用意して比較グラフを作成します.

ライブラリ化

gcc -c calculate.c -o calculate.o
ar rcs libCalculate.a calculate.o

今回は静的ライブラリとして作成しました.

使い方

test.c
#include <stdio.h>
#include "calculate.h"

int main(){
    multiFilePlotter(3,"euler.txt","runge.txt","answer.txt");
    return 0;
}
gcc test.c -L. -lcalculate -o test
./test

-L.オプションはライブラリが存在するディレクトリを示す必要があります.
L.では現在のディレクトリを指定していることになります.

感想

ライブラリとか作ったことなかったので,完成はしましたが細かいことはよくわかってません.
静的ライブラリと動的ライブラリの違いや,コマンドの詳細な意味(例えば-lcalculateは自由につけれる名前で適当につけたが,使う場面がないからなぜ名付けたかわかってない.)などがわかっていません.
これで多少はコーディングが楽になることを祈ります.
githubとかで一般公開してもいいですが,面倒なので今はしません.
それと,今回のライブラリはライブラリといえるほど汎用性が高くありません.
例外処理がほとんど記載されていないのです.結構致命的.
具体的にはファイルの中身の行数が同じじゃないといけなかったり,ラベルの指定ができなかったりと...かなり限定的な用途でしか用いることができないので公開はしません.

一言

プログラマーは楽をするために苦労する生き物だなぁ.

付録

ソースコード全部添付しときます.
それとおまけで作ったグラフを1つ添付.

calculate.h
#ifndef CALCULATE_H
#define CALCULATE_H

void calculate_error(const char *file, const char *file1, const char *file2);
int aFilePlotter(const char *file);
int multiFilePlotter(int numFiles, ...);

#endif
calculate.c
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include "calculate.h"

void calcurlate_error(const char *file, const char *file1, const char *file2){
    FILE *fp = fopen(file,"w");
    FILE *fp1 = fopen(file1,"r");
    FILE *fp2 = fopen(file2,"r");
    
    if(fp1 == NULL || fp2 == NULL){
        printf("file null error");
        return;
    }

    double x1,x2,y1,y2;
    double error;
    while(fscanf(fp1,"%lf,%lf",&x1,&y1) == 2 && fscanf(fp2,"%lf,%lf",&x2,&y2) == 2){
        if(fabs(x1 - x2) > 1e-6){
            printf("xの値が一致しません");
            break;
        }
        error = fabs(y1 - y2);
        printf("%8.3lf,%8.5lf\n",x1,error);
        fprintf(fp,"%8.3lf,%8.5lf\n",x1,error);
    }
    
    fclose(fp);
    fclose(fp1);
    fclose(fp2);
}

int aFilePlotter(const char *file){
    FILE *gp;
    gp = popen("gnuplot -persist","w");
    fprintf(gp,"set multiplot\n");
    fprintf(gp,"set datafile separator ','");
    //fprintf(gp,"set xrange[0:2]\n");
    //fprintf(gp,"set yrange[0:0.6]\n");
    fprintf(gp,"set xlabel 't'\n");
    fprintf(gp,"set ylabel 'y(t)'\n");
    fprintf(gp,"plot '%s' with line\n",file);
    fprintf(gp,"quit\n");
    pclose(gp);
    
    return 0;
}

int multiFilePlotter(int numFiles, ...)
{
    FILE *gp;
    gp = popen("gnuplot -persist","w");
    if(gp == NULL){
        fprintf(stderr, "Error: Could not open gnuplot\n");
        return -1;
    }

    fprintf(gp,"set multiplot\n");
    
    //fprintf(gp,"set xrange[0:2]\n");
    //fprintf(gp,"set yrange[0:0.6]\n");
    fprintf(gp,"set xlabel 't'\n");
    fprintf(gp,"set ylabel 'y(t)'\n");
    va_list args;
    va_start(args, numFiles);
    fprintf(gp, "plot ");
    for(int i = 0; i < numFiles; i++){
       const char *file = va_arg(args, const char*);
       fprintf(gp, "'%s' with lines", file);
       if(i < numFiles - 1){
        fprintf(gp, ", ");
       }
    }
    fprintf(gp,"\n"); 
    va_end(args);
    fprintf(gp,"quit\n");
    pclose(gp);

    return 0;
}

ライブラリを用いて作成したグラフ.
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?