gnuplot: kenar boşluğu olmayan piksel başına bir 2D dizi öğesinin çizilmesi


9

Kenar boşlukları, kenarlıklar veya eksenler ile veri 2D bir dizi çizmek için gnuplot 5.0 kullanmaya çalışıyorum ... sadece bazı verileri temsil eden bir 2D görüntü (.png veya .jpg). Ben istiyorum görüntüde tam olarak bir piksele tekabül her dizi elemanı ile hiçbir ölçeklendirme / enterpolasyon vb ve kenarlarında hiçbir ekstra beyaz piksel.

Şimdiye kadar, kenar boşluklarını 0 olarak ayarlamaya ve hatta pixelsbayrağı kullanmaya çalıştığımda , görüntünün sağ ve üst kenarlarında bir dizi beyaz piksel bırakıyorum.

Bir veri dizisinin piksel piksel gösterimi ve ekstra bir şey olmayan bir görüntü dosyasını nasıl alabilirim?

gnuplot betiği:

#!/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'dan örnek veriler:

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

ekstra pikseller


verilerin x y zliste formatında olması kabul edilebilir mi?
theozh

Yanıtlar:


5

Bazı gnuplot terminalleri, görüntüyü içeren ayrı bir png dosyası oluşturarak ve ardından ortaya çıkan grafiğin içine bağlayarak "görüntü ile" uygular. Bu ayrı png görüntü dosyasını doğrudan kullanmak, sayfa düzeni, kenar boşlukları vb. Sorunları önleyecektir. Burada tuval terminalini kullanıyorum. Arsa kendisi atılır; tek tutmamız gereken içerikle oluşturulan png dosyası.

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

Bu kısa ve hızlı ve işe yarıyor! Henüz başaramadığım tek şey: 1. Windows'ta çıktıdan kaçının, 2. png dosyasına dizin olmadan kendi adımı verin ya da en azından arsa yeniden yarattığınızda png dosyasının dizinini artırmayı bırakın.
theozh

Windows çıktılarında yardımcı olamıyorum. Tuval terminalindeki sayaç hakkında haklısın; asla sıfırlanmaz. Ama aynı hile ile oynayabilirsiniz set term tikz externalimagesve bu terminal her "belirlenmiş terim "de sayacı sıfırlar. Sen kullanamaz set output "/dev/null"TikZ ile, ama bu sizin için bastırmak çıkışına işi yapmazsa o zaman umurumda olmayabilir. Tkcanvas ve svg terminalleri diğer olasılıklardır, ancak bunlarda harici png mekanizması gnuplot sürümüne ve derleme seçeneklerine bağlıdır.
Ethan

Harika çalışıyor! Aslında sonra biraz yeniden adlandırma gereklidir, ama sonunda aradığım gibi bir piksel tam görüntü dosyası alıyorum. Teşekkürler!
HotDogCannon

3

Gnuplot kullanmayın.

Bunun yerine, verilerinizi okuyan ve Taşınabilir Anymap biçimlerinden birine dönüştüren bir komut dosyası yazın . İşte Python'da bir örnek:

#!/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()

Veri dosyasını oluşturan programı değiştirebilirseniz, yukarıdaki adımı atlayabilir ve bunun yerine verileri doğrudan PNM formatında oluşturabilirsiniz.

Her iki durumda da, görüntüyü istediğiniz bir biçime dönüştürmek için ImageMagick'i kullanabilirsiniz:

./convert.py | convert - pic.png

1
Aslında bu tür bir görev için Gnuplot kullanmak, bir şeye çivi çakmak için bir kitap kullanmak gibidir. Çalışabilir, ancak bu görev için kitaplar yapılmaz. Tercih ettiğim araç , "GNU" etki alanında kalmak için GNU Octave olacaktır :) Bu imwriteişlev, 2D verileri bir PNG görüntüsü olarak kaydetmek için kullanılabilir.
blerontin

Bu ilginç bir rota ve kesinlikle değerli bir yedekleme, ama kullanmayacağım gnuplot, o zaman ben sadece matplotlibbunun yerine kullanacağım (aşağıdaki cevabım bakınız). Bu büyük bir katkıdır, ancak teknik olarak soru / ödül gnuplotbu özel görev için uygun göründüğü kadar uygun olmayan bir çözüm ister .
HotDogCannon

3

Bu kolay bir görev olmalı, ancak görünüşe göre öyle değil. Diğer tüm girişimler başarısız olduğu için aşağıdakiler (hantal) bir çözüm olabilir. Benim şüphem bazı grafik kütüphanesinde bir gnuplot kullanıcısı olarak çözemeyeceğiniz bir sorun olması.

ASCII matris verilerinin de iyi olduğunu söylediniz. Buradaki "hile" with lines, verilerin boş satırlarla "kesildiği" verileri, temel olarak tek nokta çizerek çizmektir. Veri dosyanız 1: 1'i bir veritabanına almanız gerektiğinde bunu kontrol edin .

Zaten tuhaf yeterli değilse Ancak, için işe görünüyor pngve gifuç ama için pngcairoya wxt. Geçici çözüm muhtemelen yavaş ve verimsiz ama en azından istenen çıktıyı oluşturur sanırım. Boyutta bir sınır olup olmadığından emin değilim. Win7, gnuplot 5.2.6 ile 100x100 piksel ile test edilmiştir. Yorumlar ve geliştirmeler açıktır.

Kod:

### 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

Sonuç: (100x100 piksel)

resim açıklamasını buraya girin

(siyah arka planla büyütülmüş):

resim açıklamasını buraya girin

400x200 piksel boyutundaki resim (8 yaşındaki dizüstü bilgisayarımda yaklaşık 22 saniye sürer).

resim açıklamasını buraya girin


ve SizeX ve SizeY eşit değilse ne olur?
HotDogCannon

üzgünüm, karıştırdım xve y. Eşit SizeXve SizeYeşit değilse hala çalışıyor . Kodu düzeltirim.
theozh

Tamam, ilginç bir yaklaşım, ama ilk önce Fortran'dan sizin gibi bir diziye veya akışa ikili verileri nasıl okurum Data2?
HotDogCannon

Bir şekilde test etmek için kayan nokta verileri içeren bir 400x200 ikili dosya sağlayabilir misiniz?
theozh

1

Aslında soru / lütuf bir gnuplotçözüm istese bile ihtiyacım olanı almak için kullanarak sona erdi :

matplotlibaradığımı yapan bir fonksiyon matplotlib.pyplot.imsave vardır ... yani 'sadece veri pikselleri' çizmek ve kenarlıklar, kenar boşlukları, eksenler gibi ekstralar yok. Aslında sadece matplotlib.pyplot.imshow hakkında biliyordum ve görüntü dosyasındaki tüm ekstraları ortadan kaldırmak ve enterpolasyon / yumuşatma vb. önlemek için çok sayıda hile çekin (ve bu nedenle gnuplotbelirli bir noktaya döndü ). İle imsaveoldukça kolaydır, bu yüzden kullanmaya geri döndüm matplotlib'tam piksel' için solüsyon (renk haritası, ölçekleme, vs açısından) kolay henüz için araziler hala esnek. İşte bir örnek:

#!/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')

1

Tamam, işte başka bir olası çözüm (ilk hantal yaklaşımımdan ayırdım). Parseleyi hemen bir saniyeden az bir sürede oluşturur. Yeniden adlandırma veya gereksiz bir dosya oluşturmaya gerek yok.

Sanırım anahtar kullanmak term pngve ps 0.1.

Kanıtım yok ama sanırım ps 1ca. 6 piksel genişliğinde ve köşede üst üste binme ve / veya beyaz pikseller oluşturur. Yine, her ne sebeple olursa olsun, onunla çalışıyor gibi görünüyor term pngama değil term pngcairo.

Ne test (Win7, gnuplot 5.2.6) 00 00 FFtekrar tekrar desen sahip bir ikili dosya (burada boş bayt görüntüleyemiyorum). Gnuplot format="%d", dizi öğesi ( ) başına 4 bayt okuduğu için , eğer çiziyorsam, bu alternatif bir RGB desenine yol açar with lc rgb var.

Aynı şekilde (umarım) format="%f"bir renk paleti ile birlikte nasıl okunacağını ve kullanılacağını bulabiliriz. Aradığın şey bu, değil mi? Daha fazla test sonucu, yorum, iyileştirme ve açıklama kabul edilir.

Kod:

### 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

Sonuç:

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.