Javaでのグラフ作成について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
bun

Javaでのグラフ作成について

#1

投稿記事 by bun » 15年前

C言語に限らないということなので、Javaについて質問させていただきます。
今、円グラフの作成に取り掛かっているのですがいくつかわからないことがでてきました。
以下にまとめます。

1,今のソースでは12等分したいが12等分されない。
2,円周率で生じる誤差をどのように修正したら良いのか?
3,fillOvalをどのように組み込めばよいかわからない。
目指したい円グラフをエクセルで作成して画像で上げておきます。

現段階のソースは以下の通りです。
12個の値は適当にいれてやっているのですが、12等分されない現状です。
import java.applet.Applet;
import java.awt.*;


    
  public class CircleGraph extends Applet {
  int pa[/url]=new int[12];

  public void init() {
     setBackground(new Color(255,255,255));
     pa[0]=;pa[1]=;pa[2]=;pa[3]=;pa[4]=;pa[5]=;
     pa[6]=;pa[7]=;pa[8]=;pa[9]=;pa[10]=;pa[11]=;
   }


 public void paint(Graphics g) {
     g.drawOval(50,50,300,300); 
     int i,x1,y1,sum,deg,r=150;
     sum=0;
     for(i=0;i<12;i++){
          sum=sum+pa;
    }
     for(i=0;i<12;i++){
     deg=pa*360/sum ;
     if(i>=1){
     deg=pa*360/sum+pa[i-1]*360/sum ;
     double rad=150*Math.PI*deg/360;
     x1=(int)(200+r*Math.cos(rad));
     y1=(int)(200-r*Math.sin(rad));
     g.drawLine(200,200,x1,y1);
     }     
 }
  }
 
}

ookami

Re:Javaでのグラフ作成について

#2

投稿記事 by ookami » 15年前

とりあえず1のみの回答ですみませんが…

まず、PI(ラジアン)=180度なので、

double rad=150*Math.PI*deg/360;

double rad=Math.PI*deg/180;

ですね。

あと、

deg=pa*360/sum+pa[i-1]*360/sum ;

のところは、「今の値に前回値を足した値」ではなく「i番目までの合計値」ではないでしょうか。

また、円と線分の中心がずれているようです。

たいちう

Re:Javaでのグラフ作成について

#3

投稿記事 by たいちう » 15年前

> 12個の値は適当にいれてやっているのですが、12等分されない現状です。

適当じゃ駄目でしょ。適切に入れてますか?
Javaが動く環境がないのですが、次のように変えて試してください。
public void init() {
    setBackground(new Color(255,255,255));
    for (int i = 0; i < 12; i++) {
        pa = 30;
        // 12等分でない例
        // pa = (i % 3) ? 15 : ((i % 3 == 1) ? 30 : 45);
    }
}

public void paint(Graphics g) {
    g.drawOval(50,50,350,350);
    int i,x1,y1,sum,deg,r=150;
    sum=0;
    for(i=0;i<12;i++){
        double rad=2*Math.PI*sum/360;
        x1=(int)(200+r*Math.cos(rad));
        y1=(int)(200-r*Math.sin(rad));
        g.drawLine(200,200,x1,y1);
        sum=sum+pa;
    }
}

たいちう

Re:Javaでのグラフ作成について

#4

投稿記事 by たいちう » 15年前

> 2,円周率で生じる誤差をどのように修正したら良いのか?

円周率の誤差については誤差が蓄積されないようにするとか、
当たり前の事しか言えません。これ以上はケースバイケースですので、
具体的なソースコードなどを元にしないとアドバイスはしにくいです。

憶測ですが、別の原因でプログラムが思う通りに動かないのも
誤差のせいにしていませんか?


> 3,fillOvalをどのように組み込めばよいかわからない。

fillArcを使ったほうが良いでしょう。
http://www.ics.kagoshima-u.ac.jp/edu/ta ... ogram.html

bun

Re:Javaでのグラフ作成について

#5

投稿記事 by bun » 15年前

JAVA環境のある別PCからの書き込みです。
12等分することはできましたが、それぞれの値ごとに円弧内を塗ることができません。
fillarcの中の数値がおかしいのだとは思いますが・・・
アドバイスお願いします。
import java.applet.Applet;
import java.awt.*;

  public class CircleGraph extends Applet {
  int pa[/url]=new int[12];

  public void init() {
     setBackground(new Color(255,255,255));
     pa[0]=180;pa[1]=120;pa[2]=83;pa[3]=112;pa[4]=90;pa[5]=109;
     pa[6]=120;pa[7]=130;pa[8]=200;pa[9]=155;pa[10]=180;pa[11]=170;
   }


 public void paint(Graphics g) {
     g.drawOval(50,50,300,300); 
     int i,x,y,x1,y1,sum,sum2,deg,deg1,r;
     r=150;
     sum=0;
     sum2=0;
     for(i=0;i<12;i++){
          sum=sum+pa;
        }
     
     deg1=pa[0]*360/sum ;
     double rad=Math.PI*deg1/180;
     x=(int)(200+r*Math.cos(rad));
     y=(int)(200-r*Math.sin(rad));
     g.drawLine(200,200,x,y);  
   for(i=1;i<12;i++){
    if(i>=1){
       sum2=sum2+pa[i-1]*360/sum;
       deg=pa*360/sum+sum2;
       
       rad=Math.PI*deg/180;
       x1=(int)(200+r*Math.cos(rad));
       y1=(int)(200-r*Math.sin(rad));
       g.setColor(new Color(0,0,0));
       g.drawLine(200,200,x1,y1);
       int R=(int)(Math.random()*256);
       int G=(int)(Math.random()*256);
       int B=(int)(Math.random()*256);
       g.setColor(new Color(R,G,B));
       g.fillArc(50,50,300,300,deg,deg+pa[i+1]*360/sum); 
  }     
 }
  }
 
}

たいちう

Re:Javaでのグラフ作成について

#6

投稿記事 by たいちう » 15年前

> 12等分することはできましたが、

本当にこのプログラムでできましたか?
ookamiさんも指摘している、

> また、円と線分の中心がずれているようです。

が直っていないですけど。


闇雲にやらず、まずはfillArcの練習をしましょう。
90度の扇形を描くことはできますか?
自由な向きで描けますか?

30度の扇形は描けますか?
60度の扇に見えるように、色違いで2つ並べて表示できますか?

ookami

Re:Javaでのグラフ作成について

#7

投稿記事 by ookami » 15年前

> 12等分することはできました

とありますが、

> pa[0]=180;pa[1]=120;pa[2]=83;pa[3]=112;pa[4]=90;pa[5]=109;
> pa[6]=120;pa[7]=130;pa[8]=200;pa[9]=155;pa[10]=180;pa[11]=170;

を見ると、12等分にはなったらおかしいのでは...?

あと、

pa[i+1]

のところでpa[12](範囲外)を参照していませんか? 画像

bun

Re:Javaでのグラフ作成について

#8

投稿記事 by bun » 15年前

大変申し訳ありませんでした。
12等分ではなく12分割でした。
fillarc等を考慮しなおして書き直してみたのですが、画像のような空白ができたりしてしまう状態になってしまいました。一つ目の部分は空白になると思うのですが・・
どこがいけないんでしょうか?
ご教授お願いいたします。
import java.applet.Applet;
import java.awt.*;

  public class CircleGraph extends Applet {
  int pa[/url]=new int[12];

  public void init() {
     setBackground(new Color(255,255,255));
     pa[0]=180;pa[1]=120;pa[2]=83;pa[3]=112;pa[4]=90;pa[5]=109;
     pa[6]=120;pa[7]=130;pa[8]=200;pa[9]=155;pa[10]=180;pa[11]=170;
   }


 public void paint(Graphics g) {
     g.drawOval(0,0,300,300); 
     int i,x,y,x1,y1,sum,sum2,deg,deg1,r;
     r=150;
     sum=0;
     sum2=0;
     for(i=0;i<12;i++){
          sum=sum+pa;
        }
     
     deg1=pa[0]*360/sum ;
     double rad=Math.PI*deg1/180;
     x=(int)(150+r*Math.cos(rad));
     y=(int)(150-r*Math.sin(rad));
     g.drawLine(150,150,x,y);  
   for(i=1;i<12;i++){
    if(i>=1){
       sum2=sum2+pa[i-1]*360/sum;
       deg=pa*360/sum+sum2;
       
       rad=Math.PI*deg/180;
       x1=(int)(150+r*Math.cos(rad));
       y1=(int)(150-r*Math.sin(rad));
       g.setColor(new Color(0,0,0));
       g.drawLine(150,150,x1,y1);
       int R=(int)(Math.random()*256);
       int G=(int)(Math.random()*256);
       int B=(int)(Math.random()*256);
       g.setColor(new Color(R,G,B));
       g.fillArc(0,0,300,300,deg,pa*360/sum); 
  }     
 }
  }
 
}
画像

ookami

Re:Javaでのグラフ作成について

#9

投稿記事 by ookami » 15年前

deg=pa*360/sum+sum2;

deg=sum2;

でどうでしょう。あと[0]の分のfillArcを足せば、骨子は出来上がりじゃないでしょうか。

あとは、「右を基点に反時計周り」で意図どおりですか?

それから、輪郭は後から描いたほうがはっきりしていいと思います。

bun

Re:Javaでのグラフ作成について

#10

投稿記事 by bun » 15年前

ありがとうございます!
形にはなりました。

しかし、空白が出てきてしまいます。
座標がint型なので整数で返してしまい、誤差が生じるのだと思います。
drawLineなどはdrawLine(int x1, int y1, int x2, int y2)のようにint型にしなければならないのでdoubleなどは使えないと思うのですが・・・
これの解決方法はあるのでしょうか?

たいちう

Re:Javaでのグラフ作成について

#11

投稿記事 by たいちう » 15年前

> 座標がint型なので整数で返してしまい、誤差が生じるのだと思います。

誤差が原因と考えるには大きすぎませんか?
最新のソースコードと実行結果を載せて下さい。

bun

Re:Javaでのグラフ作成について

#12

投稿記事 by bun » 15年前

現状をアップします。
最後の部分に空白が出てます。
import java.applet.Applet;
import java.awt.*;

  public class CircleGraph extends Applet {
  int pa[/url]=new int[12];

  public void init() {
     setBackground(new Color(255,255,255));
     pa[0]=180;pa[1]=120;pa[2]=83;pa[3]=112;pa[4]=90;pa[5]=109;
     pa[6]=120;pa[7]=130;pa[8]=200;pa[9]=155;pa[10]=180;pa[11]=170;
   }


 public void paint(Graphics g) {
     g.drawOval(0,0,300,300); 
     int i,x,y,x1,y1,sum,sum2,deg,deg1,r;
     r=150;
     sum=0;
     sum2=0;
     for(i=0;i<12;i++){
          sum=sum+pa;
        }
     
     deg1=pa[0]*360/sum ;
     double rad=Math.PI*deg1/180;
     x=(int)(150+r*Math.cos(rad));
     y=(int)(150-r*Math.sin(rad));
     g.drawLine(150,150,x,y);  
     int R=(int)(Math.random()*256);
     int G=(int)(Math.random()*256);
     int B=(int)(Math.random()*256);
     g.setColor(new Color(R,G,B));
     g.fillArc(0,0,300,300,0,pa[0]*360/sum); 

  for(i=1;i<12;i++){
    if(i>=1){
       sum2=sum2+pa[i-1]*360/sum;
       deg=sum2;
       
       rad=Math.PI*deg/180;
       x1=(int)(150+r*Math.cos(rad));
       y1=(int)(150-r*Math.sin(rad));
       g.setColor(new Color(0,0,0));
       g.drawLine(150,150,x1,y1);
       R=(int)(Math.random()*256);
       G=(int)(Math.random()*256);
       B=(int)(Math.random()*256);
       g.setColor(new Color(R,G,B));
       g.fillArc(0,0,300,300,deg,pa*360/sum); 
  }     
 }
   g.setColor(new Color(0,0,0));
   g.drawOval(0,0,300,300);   
}
 
}

ookami

Re:Javaでのグラフ作成について

#13

投稿記事 by ookami » 15年前

sum2=sum2+pa[i-1]*360/sum;
deg=sum2;



sum2=sum2+pa[i-1];
deg=sum2*360/sum;

ではどうでしょう。sum2の意味変わりますが。

box

Re:Javaでのグラフ作成について

#14

投稿記事 by box » 15年前

> for(i=1;i<12;i++){
> if(i>=1){

この前後のロジックが似通っていますよね。
同じような文を複数箇所に書くとメンテナンスしにくくなりそうです。
また、上記のforループはiが1~11の間を回るので、
if文は不要ではないでしょうか(iは1以上に決まっている)。

たいちう

Re:Javaでのグラフ作成について

#15

投稿記事 by たいちう » 15年前

誤差の蓄積ですね。
sum2の計算の際に小数点以下が切り捨てられますが、
切り捨てた後の値を12個足しても360にはなりません。
角度に関係する変数は全てdouble型で扱って、
fillArcに四捨五入して渡しましょう。
四捨五入した後の値を、その後の計算で使ってもいけません。

fillArcに渡している引数をデバッグ出力して、
思った通りに計算できているか確認してください。

boxさんも指摘しているように、似たようなロジックが複数あるのはバグの温床になります。
iが0の時とそれ以外を分ける必要はないはずですよ。
double sum = 0;
for (i = 0; i < 12; i++) {
    double deg = paを変換
    fillArc(0, 0, 300, 300, round(sum), round(sum + deg));
    sum += deg;
}

閉鎖

“C言語何でも質問掲示板” へ戻る