web-dev-qa-db-ja.com

gnuplot:マージンなしでピクセルごとに1つの2D配列要素をプロットする方法

Gnuplot 5.0を使用して、マージンや境界線や軸のないデータの2D配列をプロットしようとしています...いくつかのデータを表す2D画像(.pngまたは.jpg)だけです。 各配列要素が画像の正確に1つのピクセルに対応するようにしたいスケーリング/補間なしなどとエッジに余分な白いピクセルがない

これまでのところ、マージンを0に設定しようとすると、pixelsフラグを使用しても、画像の右側と上部の境界に白いピクセルの行が残ります。

どうすれば、データ配列のピクセルごとの表現のみを含み、余分なものは何もない画像ファイルを取得できますか?

gnuplotスクリプト:

#!/usr/bin/gnuplot --persist

set terminal png size 400, 200

set size ratio -1
set lmargin at screen 0
set rmargin at screen 1
set tmargin at screen 0
set bmargin at screen 1

unset colorbox
unset tics
unset xtics
unset ytics
unset border
unset key

set output "pic.png"

plot "T.dat" binary array=400x200 format="%f" with image pixels notitle

Fortran 90のデータ例:

program main
implicit none
integer, parameter :: nx = 400
integer, parameter :: ny = 200
real, dimension (:,:), allocatable :: T
allocate (T(nx,ny))

T(:,:)=0.500
T(2,2)=5.
T(nx-1,ny-1)=5.
T(2,ny-1)=5.
T(nx-1,2)=5.

open(3, file="T.dat", access="stream")
write(3) T(:,:)
close(3)

end program main

extra pixels

9
HotDogCannon

一部のgnuplot端末は、画像を含む個別のpngファイルを作成し、結果のプロット内でそれにリンクすることにより、「画像あり」を実装しています。その個別のpng画像ファイルを直接使用することで、ページレイアウト、マージンなどの問題を回避できます。ここではキャンバスターミナルを使用します。プロット自体は捨てられます。必要なのは、目的のコンテンツで作成されたpngファイルだけです。

gnuplot> set term canvas name 'myplot'
Terminal type is now 'canvas'
Options are ' rounded size 600,400 enhanced fsize 10 lw 1 fontscale 1 standalone'
gnuplot> set output '/dev/null'
gnuplot> plot "T.dat" binary array=400x200 format="%f" with image 
   linking image 1 to external file myplot_image_01.png
gnuplot> quit

$identify myplot_image_01.png
myplot_image_01.png PNG 400x200 400x200+0+0 8-bit sRGB 348B 0.000u 0:00.000
4
Ethan

これは簡単な作業ですが、そうではないようです。他のすべての試みが失敗したため、以下は(面倒な)解決策になる可能性があります。私の疑いは、一部のグラフィックスライブラリにgnuplotユーザーとして解決できない問題があることです。

ASCII行列データも大丈夫です。ここでの「トリック」はデータをプロットすることですwith linesここで、データは空の線によって「中断」され、基本的に単一の点を描画します。 datafile 1:1 to a datablock を取得する必要がある場合は、これを確認してください。

しかし、それがまだ十分に奇妙ではない場合、pngおよびgifターミナルでは機能するようですが、pngcairoまたはwxtでは機能しません。回避策はおそらく遅くて非効率的ですが、少なくとも望ましい出力が作成されると思います。サイズに制限があるかわかりません。 Win7、gnuplot 5.2.6で100x100ピクセルでテストされています。コメントや改善は大歓迎です。

コード:

### pixel image from matrix data without strange white border
reset session

SizeX = 100
SizeY = 100
set terminal png size SizeX,SizeY
set output "tbPixelImage.png"

# generate some random matrix data
set print $Data2
    do for [y=1:SizeY] {
        Line = ''
        do for [x=1:SizeX] {
            Line = Line.sprintf(" %9d",int(Rand(0)*0x01000000))  # random color
        }
        print Line
    }
set print
# print $Data2

# convert matrix data into x y z data with empty lines inbetween
set print $Data3
    do for [y=1:SizeY] {
        do for [x=1:SizeX] {
            print sprintf("%g %g %s", x, y, Word($Data2[y],x))
            print ""
        }
    }
set print
# print $Data3

set margins 0,0,0,0
unset colorbox
unset border
unset key
unset tics

set xrange[1:SizeX]
set yrange[1:SizeY]

plot $Data3 u 1:2:3 w l lw 1 lc rgb var notitle

set output
### end of code

結果:(100x100ピクセル)

enter image description here

(黒い背景で拡大):

enter image description here

400x200ピクセルの画像(8歳のラップトップで約22秒かかります)。

enter image description here

2
theozh

gnuplotを使用しないでください

代わりに、データを読み取って Portable Anymapフォーマット のいずれかに変換するスクリプトを作成します。 Pythonでの例を次に示します。

#!/usr/bin/env python3
import math
import struct

width = 400
height = 200
levels = 255

raw_datum_fmt = '=d' # native, binary double-precision float
raw_datum_size = struct.calcsize(raw_datum_fmt)

with open('T.dat', 'rb') as f:
    print("P2")
    print("{} {}".format(width, height))
    print("{}".format(levels))

    raw_data = f.read(width * height * raw_datum_size)

    for y in range(height):
        for x in range(width):
            raw_datum, = struct.unpack_from(raw_datum_fmt, raw_data, (y * width + x) * raw_datum_size)
            datum = math.floor(raw_datum * levels) # assume a number in the range [0, 1]
            print("{:>3} ".format(datum), end='')
        print()

データファイルを生成するプログラムを変更できる場合は、上記の手順をスキップして、PNM形式でデータを直接生成することもできます。

どちらの方法でも、ImageMagickを使用して、画像を選択した形式に変換できます。

./convert.py | convert - pic.png
2
user3840170

質問/バウンティがgnuplotソリューションを求めているにもかかわらず、私が最終的に必要なものを得るために実際に使用したもの

matplotlibには関数があります matplotlib.pyplot.imsave これは私が探していたものを実行します...つまり、「データピクセルのみ」をプロットし、境界線、マージン、軸などの余分なものはプロットしません。元々私は matplotlib.pyplot.imshow についてのみ知っていて、画像ファイルからすべての余分なものを排除し、補間/スムージングなどを防ぐために多くのトリックを引き出す必要がありました(したがって、gnuplot特定の時点)。 imsaveを使用すると、かなり簡単です。そのため、「カラーマッピング」や「スケーリング」などの点で「ピクセルに正確」なプロットを簡単かつ柔軟に解決するには、matplotlibを使用します。次に例を示します。

#!/usr/bin/env python3

import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

nx = 400
ny = 200

data = np.fromfile('T.dat', dtype=np.float32, count=nx*ny)
data = data.reshape((nx,ny), order='F')
matplotlib.image.imsave('T.png', np.transpose(data), Origin='lower', format='png')
0
HotDogCannon

さて、ここに別の可能な解決策があります(私はそれを私の最初の厄介なアプローチから分離しました)。 1秒未満ですぐにプロットが作成されます。名前の変更や不要なファイルの作成は不要です。

キーはterm pngps 0.1を使用することだと思います。

証明はありませんが、ps 1はおよそだと思います。 6ピクセルの大きさで、一部が重なり合うか、コーナーに白いピクセルが作成されます。繰り返しになりますが、何らかの理由でterm pngでは機能するようですが、term pngcairoでは機能しないようです。

私がテストしたもの(Win7、gnuplot 5.2.6)は、パターン00 00 FFがすべて繰り返されたバイナリファイルです(ここではnullバイトを表示できません)。 gnuplotは配列項目(format="%d")ごとに4バイトを読み取るため、with lc rgb varをプロットすると、RGBパターンが交互になります。

同じ方法で(うまくいけば)format="%f"を読み取ってカラーパレットと一緒に使用する方法を理解できます。それがあなたが探しているものだと思いますよね?さらなるテスト結果、コメント、改善、説明を歓迎します。

コード:

### pixel image from matrix data without strange white border
reset session

SizeX = 400
SizeY = 200
set terminal png size SizeX,SizeY
set output "tbPixelImage.png"

set margins 0,0,0,0
unset colorbox
unset border
unset key
unset tics

set xrange[0:SizeX-1]
set yrange[0:SizeY-1]

plot "tbBinary.dat" binary array=(SizeX,SizeY) format="%d" w p pt 5 ps 0.1 lc rgb var
### end of code

結果:

enter image description here

0
theozh