• ベストアンサー

C#での散布図の書き方

C#での散布図の書き方 C#を使って 横軸をx座標、縦軸をy座標として散布図を書きたいのですが 良い方法はありますでしょうか?;; 困り果てております;; お願いします;;

質問者が選んだベストアンサー

  • ベストアンサー
  • hiropuri
  • ベストアンサー率55% (24/43)
回答No.2

質問がありましたので再度記述させて頂きます。 「paintイベント上に記述」とは、デザイナ上からPaintイベントを追加する、 という意味です。 もしくは、下記のように記述して Paint イベントハンドラを オーバーライドしてもOKかと思います。 protected override void OnPaint(PaintEventArgs pea) { Point[] pt = new Point[100]; // 座標を格納する変数 Random rnd = new Random(); //テスト用:乱数生成用です // ※テスト用にランダムな座標を格納 for (int i = 0; i < pt.Length; i++) { pt[i].X = rnd.Next(this.Width); pt[i].Y = rnd.Next(this.Height); } // ↓ここからが実際の処理 Graphics g = this.CreateGraphics(); Bitmap bm = new Bitmap(this.Width, this.Height); // 全ての座標について点を描画する for (int i = 0; i < pt.Length; i++) { bm.SetPixel(pt[i].X, pt[i].Y, Color.Red); } g.DrawImage(bm, new Point(0, 0)); } ※上記を適当に貼り付ければ、動きは見られると思います。 ですが、あくまでもサンプルなので「あやしいコードだ!」と思って下さい。 軽く動かす程度にとどめて、より良いプログラムを作られる事を願っております(^^

saclover
質問者

補足

補足説明有難うございます! 実行してみたところ薄い点が何個も現われました。。 このような感じで点の大きさをもっと大きくしたいと思います。 ですがついでにもうちょっと伺いたい事が・・ (1)クラスター分析を行っていまして、入力した座標をあのように点で表示できれば良いのですが、 座標入力ボタンを作って入力しているのでそのボタンを押したら点が現われるみたいな感じにしたいと思っております。その場合はどうすれば・・;; (2)さきほどのサンプルだとフォーム上?に点が現われましたが、あそこにはたくさんのボタンをつけているのであそこには表示したうないです; 他の場所に出すことは可能なのでしょうか? まだお聞きしたい事があったように思いますが、また思い出した時に聞かせて頂きたいです; 上記の点、宜しくお願い致します;;

その他の回答 (4)

  • hiropuri
  • ベストアンサー率55% (24/43)
回答No.5

(1)点が小さすぎる 今まで自分が提示してきた例では、実は2つの方法が あった事を思い返してもらえると助かります。 a)Bitmapオブジェクトを生成して、そこに描画。 次にコントロール(orフォーム)のGraphicsオブジェクトを 取得し、それにBitmapオブジェクトに渡す。結果、 コントロール上(orフォーム上)に点が描画される方法 Bitmap bm = new Bitmap(this.Width, this.Height); g.DrawImage(bm, new Point(0, 0)); ……という形 b)コントロール(orフォーム)のGraphicsオブジェクトを 取得して、そのまま簡単に描画する方法 Graphics g = pic01.CreateGraphics(); g.FillEllipse……という形 なぜ2種類提示したかというと、Graphicsオブジェクトには 「1pixelだけ描画する」メソッドが見当たらなかったからです。 1pixelだけ描画するには、Bitmapオブジェクトの SetPixe を 使うのが手っ取り早いかな~って、それだけ(^^; なので、b)の方が簡単です。Bitmapオブジェクトが不要なので。 点の描画には、 Graphicsオブジェクトの FillRectangle(矩形描画) や FillEllipse(円描画) 等が利用できます。描画サイズや色の指定も可能です。 (例) SolidBrush brs = new SolidBrush(Color.FromArgb(0x00, 0xff, 0x00)); // 緑 Graphics g = pic01.CreateGraphics(); int ptSize = 4; // 点のサイズ g.FillEllipse(brs, 0-(ptSize/2), 0-(ptSize/2), ptSize, ptSize); これで、原点(0,0)を中心とした直径4ピクセルの円が描画されます。 半径ぶんをマイナスしないと中心点がズレる事にご注意を。 (2)PCの座標系は左上原点です。数学の左下原点とは勝手が違う ように思えますが、実は大した問題ではありません。 例えば、高さが400のpictureBoxを想像して下さい。 数学座標(0, 0) → PC座標(0, 400) 数学座標(10, 100) → PC座標(10, 300) つまり、y座標をチョコっと計算してやるだけです。 PC座標y = コントロールの高さ - 数学座標y その他にも、この手の小細工的計算をする事で遊べます。 グラフの原点を決めたり、描画倍率を変えたりとか……。 x座標に10を加算すれば、グラフ描画位置が右に10移動します。 これって、原点の右移動ですよね。座標に2をかければ2倍の サイズで描画できそうです。落ち着いて考えれば、それだけ なのです(^^ ・int型へのキャストについて 例ではintを使いましたが、それは必須ではないです。 「FillEllipse が受け取れる型」なら何でもOK!です。 各メソッドはオーバーロードされている場合がほとんどなので、 自分が使いやすい物を選ぶべきです。FillEllipse の場合は FillEllipse(Brush brush, float x, float y, float width, float height); FillEllipse(Brush brush, int x, int y, int width, int height); 等がありますので、floatの方を使うのもアリです。 ただ物理的には、モニタはpixelで構成されている事を意識して 下さい。例えば「0.7pixel」と指定した場合、実際はどこに 描画されるのか……それはC#任せ?となります。 ・SetPixel について まずBitmapオブジェクトですが、名前の通り「幅と高さがある 画像」をイメージして下さい。SetPixelは「Bitmapオブジェクト上」 の指定座標に対して1pixelを描画します。 次に g.DrawImage(bm, new Point(0, 0)); ですが、これは Point pt = new Point(0, 0); g.DrawImage(bm, pt); と全く同じですね。つまり、 bm(Bitmapオブジェクト)に描い絵を、 g(Graphicsオブジェクト)の座標(0,0)を起点として描画してね という事になります。

saclover
質問者

補足

hiropuriさん 表示できました!! 目視できるようになり、点の大きさも大きくなりました! 本当にありがとうございました! 絶対に僕だけではできませんでした;; 知らない命令や概念も教えて頂いて本当に助かりました! 11月中旬に発表会があるのでそこで存分に披露させて頂きたいと思います! ほんと何か菓子折りでもお礼さしあげたい限りです;; また何かありましたらぜひお願い致します! ここってお友達機能とかってありましたっけ;;? あったらお友達になって欲しいです;;

  • hiropuri
  • ベストアンサー率55% (24/43)
回答No.4

なるほど、そうだったんですね。 開発環境を明示しておくと、より踏み込んだ回答が得られますよ(^^ C#なので、開発環境はおそらく「Visual Studio」でしょうか。 「開発環境」と「イベント駆動型」に馴染みが無い、という事でしょうか。 「Visual Studio」をご利用と仮定して、基本的な操作等を補足させて頂きます。 ●コントロールにイベントを追加する イベント駆動型というくらいなので、様々な「イベント」に対して 処理を書くイメージです。例えば「クリックした」とか「マウスが 動いた」等、色々なイベントが存在します。 例えば「フォーム」について。どのようなイベントが存在するのか 手っ取り早く確認するには、以下の手順でOKです。 1)デザイナ(フォームやボタンを配置する画面)を開いて、 表示されているフォームをクリック(選択状態にする) 2)すると、プロパティ画面に「デザイナで選択中のコントロール」 の詳細情報が表示される。つまり、フォームの情報ですね。 3)プロパティウィンドウという名前ですが、イベントについても 取り扱っています。プロパティウィンドウの上側にある、 カミナリみたいなマークを押すと、イベントの一覧になります。 4)ずら~っとイベント一覧が表示されます。が、全てを理解する 必要はありません。実際に必要になるイベントは多くないのです。 例えば、フォームがクリックされた時に何か処理したい場合は、 「Click」というイベントに着目します。そこをダブルクリック して下さい。それだけで自動的に、イベント処理用の空コードが 追加されます。 private void Form1_Click(object sender, EventArgs e) { } ↑こんな感じですね。フォームがClickされると、この処理に 飛んできます。ここに処理を書いておけばいいわけですね。 上記手順はフォームだけでなく、他のコントロールでも同様です。 こうして、処理したいイベントを追加していく事になります。 ●プロパティについて 「属性」というと難解ですが、つまり「そのオブジェクトの状態」 を保持している変数みたいなモノです。それは色であったり、 コントロールの幅や高さであったり。 テキストボックスを例に考えます。 デザイナでテキストボックスを配置した後、プロパティウィンドウを 見て下さい。様々なプロパティが表示されていると思います。 よく使うのは「Text」プロパティで、ここに、テキストボックスに 表示されている文字列が格納されています。つまり、ここを 参照すれば、ユーザが入力した文字列を取得できるという事です。 (例)string buf = textbox1.Text; // 表示中の文字列を取得する ●描画関係の話 基本的に、Graphicsオブジェクトを利用する事になります。 各コントロール毎にGraphicsオブジェクトを持っているんだなぁ、 くらいに考えて下さい。フォーム上に線を引きたければ、フォームの Graphicsオブジェクトを取得。そのGraphicsオブジェクトが、 各種の描画関係メソッドを持っています(FillEllipse など) (参考) Draw~ は塗りつぶし無しの描画関係メソッドです。 線を描画するので Pen オブジェクトが必要となります。 Fill~ は塗りつぶし有りの描画関係メソッドです。 塗りつぶすので Brush オブジェクトが必要となります。 ●いつ描画すればいいのか? 例えば「ボタンを押した時に描画する」でも構いませんが、 それだと「一度だけ描画して終わり」です。他ウィンドウの 裏に隠れた後に最前面にもってくると、描画したモノは全て 消えている……という状態に。 なので「描画が必要になった時に描画する」必要があります。 それが Paint イベントです。無効領域が発生したので描画が 必要だよ!という時に発生するイベントなので、描画関係は Paint イベント内に記述する事が多いかと思います。 前述した方法で、Paintイベントを追加すればOKですよね。 上記の情報で、 ・ユーザの様々なアクションに対応した処理を実施する ・ユーザの入力した座標(文字列)を取得する ・指定のコントロール上に点や線を描画する という事が可能です。ご希望の処理が実装できる……と、 思います、たぶん(^^; 判り難い点も多々あると思いますが。 経験者という事で、アルゴリズム的な話は無くてもOKと 思います。後は慣れの問題だけですので、頑張って下さい!

saclover
質問者

補足

本当に詳しいご説明有難う御座います;; かなり助けられております;; 本当に素晴らしい的確なご説明素晴らしい限りです;; 感謝でいっぱいです; あれから参考にさせて頂いて自分で進めた結果 pictureBoXをクリックすると何かしらの点が現われるようになりました; 一応これらの点は入力したx、y座標の散布図のようなものを期待しているのですが 問題がありまして・・ (1)点が小さすぎる・・ 小さすぎて確認できません;; この点のサイズを変更と蚊はできるのでしょうか? (2)座標軸の原点がどうやら左上にあるようですね;; これを正常な右上がりグラフにするにはどうすれば・・;; ちなみにpictureBoxの今現在のソースを添付しておきます; private void pictureBox1_Click(object sender, EventArgs e) { Point[] pt = new Point[100]; // 座標を格納する変数 for (int i = 0; i < kosu_i; i++) { pt[i].X = (int)data_d[i, 0]; pt[i].Y = (int)data_d[i, 1]; } // ↓ここからが実際の処理 pictureBox1.Refresh(); // 念の為、描画した点を消去する Graphics g = pictureBox1.CreateGraphics(); Bitmap bm = new Bitmap(pictureBox1.Width, pictureBox1.Height); // 全ての座標について点を描画する for (int i = 0; i < kosu_i; i++) { bm.SetPixel(pt[i].X, pt[i].Y, Color.Red); } g.DrawImage(bm, new Point(0, 0)); } data_d[ , ]は2次元配列となっていて [0,0]:データ0のx座標 [0,1]:データ0のy座標 をあらわしております; ちなみにdata_dはdouble型なのでint型のpt[]に代入する際にintにキャストしているという問題が生じております; あと確認させて頂きたいことがあるのですが SetPixeは指定したpt[i].X, pt[i].に色を配置するという意味で DrawImageでbmを指定することによりSetPixelで格納したピクセルに色を描画する という意味でよろしいのですよね? その際DrawImageで指定しているnew Point(0,0)はどういうことなのでしょうか;; ご質問ばかり本当に申し訳ありません;><

  • hiropuri
  • ベストアンサー率55% (24/43)
回答No.3

またまた失礼します。ご質問を頂いたので……。 先ほどのソースコードは、フォーム自体に描画していました。 例えば、ピクチャーボックスを配置して、そこの中に描画したい! という場合でも、ちょっとした応用で実現可能です。 // ※pic01はピクチャーボックスの名前です pic01.Refresh(); // 念の為、描画した点を消去する int ptSize = 8; // 描画する点の直径 Graphics g = pic01.CreateGraphics(); SolidBrush brs = new SolidBrush(Color.Red); for (int i = 0; i < pt.Length; i++) { g.FillEllipse(brs, pt[i].X - ptSize / 2, pt[i].Y - ptSize / 2, ptSize, ptSize); } brs.Dispose(); //brushオブジェクトの解放 FillEllipse は「塗りつぶした円」を描画するメソッドです。 お話していて感じたのですが、C#、もしくはプログラミングは 初めてでしょうか? 現状ですと、処理を実装していくには、 ほんの僅かに基礎が不足しているように感じるのです。 1)フォーム上に以下のオブジェクトを配置(デザイナにて) ・点を描画する為のコントロール(PictureBoxなど) ・ユーザが座標を入力をする為のTextBoxを2つ(x,y) ・描画実行!みたいなButton 2)ButtonにClickイベントを追加 3)ButtonでClickイベント内に、 ・TextBoxに入力されている文字を取得して ・それを数値に変換する ・座標として変数に格納する 4)格納されている座標を参照して、PictureBoxに点を描画する という雰囲気になると思います。もし、上記の中でイメージが 全く沸かない、どう記述したらいいか判らないといった処理が あるとしたら、この先を作り続ける事は非常に困難だと思うのです。 どうか遠回りとは思わずに、もう少し基本的な部分を……例えば、 イベントやメソッドについてweb等で調べつつ、色々とお試しに なる事をおすすめしたいです。苦手意識を持つ必要はありません、 C#は決して難しくないので大丈夫ですよ(^^ ・イベント ・プロパティ ・メソッド これらのキーワードを足がかりにするといいかもしれません。

saclover
質問者

補足

ホントにご丁寧にありがとうございます;; 高専生なのでプログラミングは4年間ほどやっておりますよ^^ ですがこれまでC中心だったのとjavaを1年ほどかじっただけで C#はあまり詳しく知りませんでした;; 特にイベントのあたりがよく分からなくて;; 教えて頂いて参考にしたいと思います; ありがとうございました!

  • hiropuri
  • ベストアンサー率55% (24/43)
回答No.1

C#にて「点を描画したい」という事でよろしいでしょうか? 例えば、フォーム上に直接「指定した点」を描画する場合を考えます。 次のコードを、フォームのPaintイベントに記述すればOKかと思います。 Graphics g = this.CreateGraphics(); Bitmap bm = new Bitmap(this.Width, this.Height); for (int i = 0; i < pt.Length; i++) { // ※pt[] はPoint型の配列で、既にデータが入っているものとします bm.SetPixel(pt[i].X, pt[i].Y, Color.Red); } g.DrawImage(bm, new Point(0, 0)); こんな感じになるかと思うのですが、どうでしょうか?

saclover
質問者

補足

ご回答有難うございます! やってみたいのですが・・ paintイベント上に記述とは・・;どうすればいのでしょうか? あまり詳しくないもので;; 教えて頂けると助かります;;

関連するQ&A

専門家に質問してみよう