【VB.NET】グラフの一部を切り取って高速表示する<dobon.net様に感謝>

昨年夏から、学習しているVB.NETですが、見様見真似でコピペしてグラフ描画プログロムを作ってきたのですが、今夏は、もう少し迫力あるリアルタイムグラフにしたいと考えてます。
●やりたいこと
「時系列で動くグラフで自由に切り取り高速表示できるグラフ」
にするためには、見様見真似ではできないので、基礎学習から初めてます。私のVB.NETの学習は、dobon.net様の記事で80%学習させていただいてます。
学習したいこと1:データ全体をbitmapへ描画してしまってから、一部を切り取って表示する
学習したいこと2:上記切り取り動作をリアルタイムで行うことで、常にグラフの中央に最新のプロットが表示されるようにする
●結果(一番最後に記載)
スライドバーで切り取るプログラムを作って操作するとめちゃくちゃ速く描画します。
データを1個ずつプロットしていたらこんな速度は出ませんので、Bitmapを予め作っておいて
それを切り取って表示するグラフ表示方法は、リアルタイムなど動くグラフでは必須アイテムだと感じました。19秒の動画をご覧ください

※2022年2月追記
本記事から8か月後にこのような作品が作れました。切り取りテクニックを駆使してます。

 

 

 

●dobon.net様の「プログラムで画像を動的に作成する」が基本

こちらの記事を見ながら作りました。https://dobon.net/vb/dotnet/graphics/createimage.html

上記ページ中段にあるオリジナルサンプルプログラムに 私の学習メモ書きしました。

'Imports System.Drawing
'PictureBox.ImageプログラミングにImageオブジェクトを設定する 
If PictureBox1.Image Is Nothing Then=>ここは、過去画像を残すために初回だけPicturBox1.Image定義
    PictureBox1.Image = New Bitmap(100, 50)
=>Pictureboxに表示するものをImageと呼びます。ここではBitmapをImageに定義してます。
End If
'ImageオブジェクトのGraphicsオブジェクトを作成する
=>graphicオブジェクトを使うのは、図形や文字を描画する目的で使います。
Dim g As Graphics = Graphics.FromImage(PictureBox1.Image)
=>ここから下は、Graphic命令をどんどん追加していけば描画できます
'全体を白で塗りつぶす
g.FillRectangle(Brushes.White, g.VisibleClipBounds)
'現在の時刻を描画する
g.DrawString(DateTime.Now.ToLongTimeString(), _
             SystemFonts.DefaultFont, Brushes.Black, 10, 10)

'Graphicsオブジェクトのリソースを解放する
g.Dispose()

'Imageプロパティの変更を反映させるために、PictureBox1を再描画する
PictureBox1.Invalidate()

●上記基本グラフプログラムから画像の一部を切り取る学習
dobon.net様
「画像の一部を切り取って(トリミングして)表示する」
https://dobon.net/vb/dotnet/graphics/triming.html

上記ページにあるオリジナルサンプルプログラムに 私の学習メモ書きしました。
学習したこと1:Bitmapを元データ用(img)と切取り用(canvas)の2個用意する
学習したこと2:元データBitmap(img)をg.DrawImgaeを使ってpixel単位で切取り処理を行う
学習したこと3:切り取り元サイズ(srcRect)と貼り付ける場所サイズ(desRect)を作る
学習したこと4:PictureBox1.ImageにBitmap canvasを書き込むと表示される

'Imports System.Drawing

'画像の一部を切り取って(トリミングして)表示する

'描画先とするImageオブジェクトを作成する

Dim canvas As New Bitmap(PictureBox1.Width, PictureBox1.Height)
=>切り取った画像を貼るBitmapとして canvasを作成

‘ImageオブジェクトのGraphicsオブジェクトを作成する

Dim g As Graphics = Graphics.FromImage(canvas)
=>Bitmapのcanvasに図形を描画するためにGraphicsgを作成

'画像ファイルのImageオブジェクトを作成する
Dim img As New Bitmap("C:\test\1.jpg")

=>ここでは外部からjpg画像を読み込んでBitmapとしている

'切り取る部分の範囲を決定する。ここでは、位置(10,10)、大きさ100x100
Dim srcRect As New Rectangle(10, 10, 100, 100)

=>Rectangle構造体というデータ構造で切取りサイズを定義している

'描画する部分の範囲を決定する。ここでは、位置(0,0)、大きさ100x100で描画する
Dim desRect As New Rectangle(0, 0, srcRect.Width, srcRect.Height)

=>描画部分もRectangle構造体で定義

'画像の一部を描画する
g.DrawImage(img, desRect, srcRect, GraphicsUnit.Pixel)

=>DrawImageは、イメージをGraphicに書き込む命令、Pixel単位でsrcRectをdesRect位置へ書き込む

'Graphicsオブジェクトのリソースを解放する
g.Dispose()

'PictureBox1に表示する
PictureBox1.Image = canvas

Graphics.DrawImage() メソッド

DrawImage(Image, Single, Single, RectangleF, GraphicsUnit)
イメージの一部を指定の位置に描画します

●自分の学習用にPgm作ってみました。
時系列グラフの時間位置を指定して切取り表示するグラフのプログラムです。

試したいこと:元のBITMAPから切り取って表示する速度非常に速いことを体感する
そこで、元データのグラフを上に表示して、下にスライドバー付の切取りグラフ
を表示するプログラムにしました。50行以下と短かくて簡単なプログラムです。
https://gist.github.com/dj1711572002/1bfacc9e6574816de848dfc1fa12a608
操作1:元グラフは、Sub Button1で作成しておく。
操作2:切り取り位置は、スライドバーで元グラフの最初から最後まで400dotで単位で切り取ることができる、切り取り開始位置は、TextBox1に表示される

■FORM1の作り方
PictureBox1,2とhScrollBar1とButton1とTextBox1の5個をToolBoxからドラッグ&ドロップして作ります。FORMのサイズは、1295x600以上です。

■プログラムの備忘録
Bitmapデータは、元グラフ用totalPlot 切取りグラフ用canvasとします。
Graphicsオブジェクトは、元グラフ加工用をtg,切取りグラフ用gとします。
元データは1200x200サイズで作って、切取りグラフは400x2001/3サイズです。

①最初に元グラフを作ります。Sub Button1_Clickでつくるので、Global変数として
元グラフで使う変数をClass直下に定義します。

Public Class Form1

Dim totalPlot As Bitmap
Dim tg As Graphics

元グラフのBitmap名:totalPlot と 元グラフを描画するGraphics名: tg
切取り動作部は、スライダーから切り取り開始番号をもらってから動作します。
dobon.net様のサンプルプログラムから元データ関係を抜いたものです。

Private Sub plotSlider(ByVal startNo As Integer)
‘画像の一部を切り取って(トリミングして)表示する
Debug.Print(startNo)’デバッグ用
Dim timeScale As Integer = 3’使ってない将来使う予定Dim canvas As New Bitmap(PictureBox1.Width, PictureBox1.Height) ‘W=400,H=240
Dim g As Graphics = Graphics.FromImage(canvas)‘ソース画像の切取り開始を(startNo,0)大きさ(400,210)とする
Dim srcRect As New Rectangle(startNo, 0, 400, 210)
描画する部分の範囲を決定する。ここでは、位置(0,0)、大きさ100×100で描画する
Dim desRect As New Rectangle(0, 0, srcRect.Width, srcRect.Height)
画像の一部を描画する
g.DrawImage(totalPlot, desRect, srcRect, GraphicsUnit.Pixel)

‘Graphicsオブジェクトのリソースを解放する
g.Dispose()‘PictureBox1に表示する
PictureBox2.Image = canvas
End Sub

③スライダーを動かして値を変える変更することで、グラフ切り取り動作が動きます。

Private Sub HScrollBar1_ValueChanged(sender As Object, e As EventArgs) Handles HScrollBar1.ValueChanged
‘maximum=1200 minimum=0
Dim slideVal As Integer = HScrollBar1.Value
plotSlider(slideVal)’切取りSUBへ位置を渡して描画させる
TextBox1.Text = CStr(slideVal)End Sub

●以後
この基本をもとにして、スキー用のグラフを改造して、スキーの現在位置からどんどん前へ進む迫力あるグラフアニメーションを作ります。

※2021年11月追記 本記事で基礎学習したBitmap切取り方法で素晴らしいグラフプログラムが
たくさんできました。

上記は、ログしたデータを動画にした例ですが、
下記は、リアルタイムグラフをBITMAPへ展開しながらリアルタイム表示して、終わった直後に
スクロールして、データチェックとカーソルで読み取りできる便利グラフツールです。

【VB.NET】リアルタイムグラフのBITMAP展開<その1小技在り>

【VB.NET】リアルタイムグラフBitmap展開<その2カーソルと拡大縮小>

【VB.NET】リアルタイムグラフBitmap展開<その3DGV経由CSV保存>

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です