質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

c言語によるグラフ作成

受付中

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 368

bayberry

score 0

!(e2c1eca5ebd75df8e1d68fb78bb32d44.png)
初めまして。
c言語で関数ポインタを使って点を表示させ、グラフを書きたいのですが点を表示させる関数のところが分かりません。
具体的には配列を作ってx座標ごとにy座標を計算して保存、これを上から表示してぐグラフに見せたいのですがどうやって書いていいのか行き詰っています。
この関数外のプログラムは以下のように書きました。
どなたか教えてください。

 #include <stdio.h>
    #include <math.h>
    int draw(int,int,int);
    int keisan( int );
    int main(){
        int max_x = 40; int max_y = 40; //x,y軸の最大値
        draw( max_x, max_y, keisan );
    }

int draw(){
//この中が分かりません
}
    int keisan( int x ){

        /return x*x;
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+1

別回答を一つ。

そのグラフを描画するエリア分の文字型の2次元配列を確保しておき、予めスペースで埋めておきます
まず、軸を配列に描画(代入、というのが正しいか)していき、次に、グラフ本体を描画します

あとはその配列の内容を文字列として1行づつ出力します

いったんこうしたグラフ描画をパターン化しておけば、他のグラフを書くのにも使いまわしができますね


と、書いてからkazuma_sさんの回答とかぶってるのに気がついて、もうちょっと追加を。
私が作るなら、

  • 二次元配列をスペースで埋める
  • 軸を描画
  • グラフの描画
  • 二次元配列を1行づつ出力
    と分けて、それぞれ一つの関数として実行できるようにさせます
    各関数は引数に、二次元配列のアドレス、Xサイズ、Yサイズ、を取るようにしておきます

そうしておけば、他のグラフを書きたいときには、3つ目の関数を差し替えるだけでいけます

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

C言語はグラフを描画するのに適していない言語です。一般にはpython, R, gnuplot, Oxyplot(C#などの.NET系)が用いられます。

Cでよく見るのはCからgnuplotを叩く例でしょうか。

いずれにせよ根本的にやり方を見なお方がいいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/16 23:20

    回答ありがとうございます。
    質問に掲載したように簡単なグラフです。今回はどうしてもc言語で書きたいのですが何か方法はありませんか?

    キャンセル

  • 2020/07/17 00:04

    やってやれなくはないでしょうが、どう考えてもCでは必要なデータを吐き出すだけにして他の言語でプロットするのが圧倒的に幸せだと思います。楽だしきれいなグラフがサクッと作れるし。プログラマーは怠惰であるべきです。

    キャンセル

  • 2020/07/17 01:19

    どうしてもというくらいなので、おそらく「そういう課題」なのでしょう。課題は自分でやりましょう。
    とりあえず、グラフにすることは置いておいて、「xが 0 からmax_x (40) まで1ずつ変化するときのyの値を配列に保存する」あたりから書いてみればいいのでは。

    キャンセル

  • 2020/07/17 01:38

    というか自分で
    > 具体的には配列を作ってx座標ごとにy座標を計算して保存
    と書いているのですから、あとはその二次元配列を上下逆にアクセスしながらprintしていけばそれっぽいものはできますよね。

    つまりなにかというと、
    int draw(int,int,int);
    int keisan( int );
    という関数分けをするのはいいけど引数がおかしい。keisanは描画対象の数学的関数を表現した関数ポインタと二次元配列へのポインタを受け取るべきだろうし、drawは二次元配列を受け取るべき。

    キャンセル

0

環境に依存しますがcursesが使えるかもしれません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

関数 f(x) のグラフを書きます。a <= x < b です。

#include <stdio.h>   // printf
#include <string.h>  // memset
#include <math.h>    // sqrt, exp, log, sin

#define A    0.0     // -1.0
#define B   25.0     // A <= x < B

double f(double x)
{
    return (x - 1) * (x - 11) * (x - 21);
    // return x;
    // return sqrt(x);
    // return sqrt(25*25 - x*x);
    // return exp(x * 0.1);
    // return log(x + 1);
    // return sin(x * 0.3);
}

#define H   25
#define W   80
#define FMT "%.79s\n"

void draw(int n, double a, double b, double *y)
{
    char scr[H][W];  // screen
    memset(scr, ' ', sizeof scr);
    double min_y = 1e99, max_y = -1e99;
    for (int i = 0; i < n; i++) {
        if (y[i] < min_y) min_y = y[i];
        if (y[i] > max_y) max_y = y[i];
    }
    double h = max_y - min_y, w = b - a;
    int x = -W * a / w, z = -H * min_y / h;
    if (x >= 0 && x < W)
        for (int i = 0; i < H; i++) scr[i][x] = '|';
    if (z >= 0 && z < H) {
        for (int i = 0; i < W; i++) scr[z][i] = '-';
        scr[z][W-2] = '>';
    }
    if (x >= 0 && x < W && z >= 0 && z < H) scr[z][x] = '+';

    for (int j = 0; j < n; j++) {
        int i = (y[j] - min_y) * H / h;
        if (i >= 0 && i < H && j >= 0 && j < W) scr[i][j] = '*';
    }
    for (int i = H; --i >= 0; ) printf(FMT, scr[i]);
}

int main(void)
{
    int n = W;
    double a = A, b = B, d = (b - a) / n, y[W];

    for (int i = 0; i < n; i++) {
        double x = a + d * i;
        y[i] = f(x);
    }
    draw(n, a, b, y);
}


追記
char scr[H][W]; をローカル変数にし、initScreen() を削除しました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/17 20:12

    コメントありがとうございます。HとWはなにか教えてほしいです。

    キャンセル

  • 2020/07/18 03:42

    height(高さ), width(幅) の意味ですが、row(行), col(列) のほうが良かったかもしれません。
    screen(画面) の縦横のサイズです。

    キャンセル

0

方法論がやっつけ感ですが,何かの参考になれば.

座標(x,y)に関して,曲線とのx方向あるいはy方向の距離がThresh以下となる場合,(x,y)の場所に*を表示するようにしています.
x方向あるいはy方向のどちらを用いるのかは関数df(曲線の傾き)の値によって決めています.

  • 面倒なので,y軸は下向を正としています.
  • 上記の方法のために,関数f(x)だけでなく,その一階導関数df(x)と,f(x)の逆関数inv_f(y)も定義しています.
  • 質問コードに見られた x*x という関数だと,xの増加に対してyの値がすごい勢いで増えていってしまうので,適当な係数alphaを乗じています.
const double alpha = 1.0 / 32;  //coefficient
double f( int x ){  return alpha * x * x;   }   //y = f(x)
double df( int x ){ return 2 * alpha * x;   }   //df(x)/dx
double inv_f( int y ){  return sqrt( y / alpha );   }   // x = inverse_of_f(y)

void draw( int max_x, int max_y, double Thresh )
{
    for( int y=0; y<=max_y; ++y )
    {
        char DefaultChar = ( y==0 ? '-' : ' ' );
        for( int x=0; x<=max_x; ++x )
        {
            double d = fabs( df(x)<=1.0   ?   ( y-f(x) )   :   ( x-inv_f(y) ) );
            char OutChar = (   (d <= Thresh)   ?   '*'   :   ( x==0 ? (y==0 ? '+' : '|') : DefaultChar )   );
            printf( "%c", OutChar );
        }
        printf( y==0 ? ">\n" : "\n" );
    }
}

int main()
{
    int max_x = 40; int max_y = 40; //x,y軸の最大値
    draw( max_x, max_y, 0.5 );
    return 0;
}

表示結果の一部(yのでかい側が切れています).
一番左上が原点(0,0)です.
*が固まって並んで「太く」見えてしまう場所が生じますが…

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/17 11:03

    Threshを小さくすると,グラフの線が途切れ途切れになります.
    Threshを大きくすると,この方法論の良くない点が浮き彫りになります.(真面目にやるなら「点(x,y)と曲線との距離」を用いるべきところだが,xあるいはyの差を用いているので,結果が「変」になる)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る