如何在 linux 中绘制二维图
How to draw 2D diagram in linux
我有一个包含要点的 .txt 文件,如下所示:
##x1 y1 x2 y2
123 567 798 900
788 900 87 89
....
我想使用 gnuplot 绘制 2D 图,其中 link 每对都与 .txt 文件对齐。
编辑1:
我找到这个 Draw points and lines in gnuplot,但我不知道如何在我的案例中使用 gnuplot。
编辑2:
图表类型没有限制。
如我所见,here 我可以使用以下方法将终端设置为 png:
set terminal png
对于线条样式,我找到了这个示例 here:
set style line 1 lc rgb '#0060ad' lt 1 lw 2 pt 7 ps 1.5
并且轴不需要标签。
已更新
根据您关于行数和最大 x,y 尺寸的答复,我在该答复底部的基于 ImageMagick 的原始方法显然不适合您的具体问题。但是,我会把它留给其他人看,因为它最多只有几十行就可以了。我现在提供一个更合适的 gnuplot
版本。
Gnuplot 版本
如果你想用 gnuplot
来做,它看起来像这样:
set terminal png size 1000,1000
set output 'result.png'
unset xtics
unset ytics
unset border
plot 'lines.txt' using 1:2:(-):(-) with vectors nohead notitle
如果将其保存在 plot.cmd
文件中,则可以 运行 使用
gnuplot < plot.cmd
如果您想要箭头,请使用如下变体:
set terminal png size 1000,1000
set output 'result.png'
set style arrow 1 heads filled size screen 0.03,15,45 ls 1
unset xtics
unset ytics
unset border
plot 'lines.txt' using 1:2:(-):(-) with vectors arrowstyle 1 notitle
Magick++ 和 C++ 答案
我决定想出一个 Magick++ 和 C++ 的答案,只是为了好玩。代码如下所示 - 编译命令显示在顶部的注释中。
////////////////////////////////////////////////////////////////////////////////
// sample.cpp
// Mark Setchell
//
// ImageMagick Magick++ sample code
//
// Compile with:
// g++ sample.cpp -o sample $(Magick++-config --cppflags --cxxflags --ldflags --libs)
////////////////////////////////////////////////////////////////////////////////
#include <Magick++.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
using namespace Magick;
int main(int argc,char **argv)
{
InitializeMagick(*argv);
// Create an image object, scaled by a factor of 100 to speed it up !
float scale=100.0;
Image image("650x650","white");
// Construct drawing list
std::list<Magick::Drawable> drawList;
// Initial settings, blue lines 1 pixel thick
drawList.push_back(DrawableStrokeColor("blue"));
drawList.push_back(DrawableStrokeWidth(1));
// Read in lines from file, expected format "x1 y1 x2 y2"
int lineno=0;
std::ifstream infile("lines.txt");
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
int x1,y1,x2,y2;
iss >> x1;
iss >> y1;
iss >> x2;
iss >> y2;
x1 = int(x1/scale);
y1 = int(x2/scale);
x2 = int(y1/scale);
y2 = int(y2/scale);
cout << "Line: " << ++lineno << " " << x1 << "," << y1 << " " << x2 << "," << y2 << endl;
// Add this point to the list of lines to draw
drawList.push_back(DrawableLine(x1,y1,x2,y2));
}
// Draw everything using completed drawing list
image.draw(drawList);
// Write the image to a file
image.write( "result.png" );
return 0;
}
我用 Perl 生成了 1,000 行随机测试数据,如下所示:
perl -E 'for($i=0;$i<1000;$i++){printf("%d %d %d %d\n",int rand 65000,int rand 65000, int rand 65000, int rand 65000);}' > lines.txt
结果如下所示:
原答案
您也可以使用已安装在大多数 Linux 发行版上的 ImageMagick 轻松完成此操作。下面其实只有4行代码——剩下的都是注释:
#!/bin/bash
# Create the output image, 1000x1000 pixels say
convert -size 1000x1000 xc:pink result.png
# Suppressing lines that have a hash (#) at the start, read in the file "lines.txt"
grep -v "^#" lines.txt | while read x1 y1 x2 y2; do
echo Read line $x1,$y1 $x2,$y2
# Tell ImageMagick to draw the line on the image
convert result.png -stroke blue -strokewidth 5 -draw "line $x1,$y1 $x2,$y2" result.png
done
输出
Read line 123,567 798,900
Read line 788,900 87,89
您也可以使用 rsvg-convert
(来自 librsvg)或 svg2png
执行此操作。这两个程序都需要 SVG 格式的 inout 文件并将其呈现为 PNG 文件。所以你需要转换你的
123 567 798 900
788 900 87 89
喜欢这种东西
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<line x1="123" y1="567" x2="798" y2="900" stroke="blue" stroke-width="1"/>
<line x1="788" y1="900" x2="87" y2="89" stroke="blue" stroke-width="1"/>
</svg>
这可以通过像这样的 awk
脚本轻松完成:
awk '
BEGIN{ printf("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n") }
{
x1=; y1=; x2=; y2=;
printf("<line x1=\"" x1 "\" y1=\"" y1 "\" x2=\"" x2 "\" y2=\"" y2 "\" stroke=\"blue\" stroke-width=\"1\"/>\n")
}
END{ printf("</svg>\n") }' points.txt
然后您可以将其输出泵入我上面提到的两个程序中的任何一个:
awk ... | rsvg-convert -b \#ffff00 > result.png
我有一个包含要点的 .txt 文件,如下所示:
##x1 y1 x2 y2
123 567 798 900
788 900 87 89
....
我想使用 gnuplot 绘制 2D 图,其中 link 每对都与 .txt 文件对齐。
编辑1:
我找到这个 Draw points and lines in gnuplot,但我不知道如何在我的案例中使用 gnuplot。
编辑2:
图表类型没有限制。 如我所见,here 我可以使用以下方法将终端设置为 png:
set terminal png
对于线条样式,我找到了这个示例 here:
set style line 1 lc rgb '#0060ad' lt 1 lw 2 pt 7 ps 1.5
并且轴不需要标签。
已更新
根据您关于行数和最大 x,y 尺寸的答复,我在该答复底部的基于 ImageMagick 的原始方法显然不适合您的具体问题。但是,我会把它留给其他人看,因为它最多只有几十行就可以了。我现在提供一个更合适的 gnuplot
版本。
Gnuplot 版本
如果你想用 gnuplot
来做,它看起来像这样:
set terminal png size 1000,1000
set output 'result.png'
unset xtics
unset ytics
unset border
plot 'lines.txt' using 1:2:(-):(-) with vectors nohead notitle
如果将其保存在 plot.cmd
文件中,则可以 运行 使用
gnuplot < plot.cmd
如果您想要箭头,请使用如下变体:
set terminal png size 1000,1000
set output 'result.png'
set style arrow 1 heads filled size screen 0.03,15,45 ls 1
unset xtics
unset ytics
unset border
plot 'lines.txt' using 1:2:(-):(-) with vectors arrowstyle 1 notitle
Magick++ 和 C++ 答案
我决定想出一个 Magick++ 和 C++ 的答案,只是为了好玩。代码如下所示 - 编译命令显示在顶部的注释中。
////////////////////////////////////////////////////////////////////////////////
// sample.cpp
// Mark Setchell
//
// ImageMagick Magick++ sample code
//
// Compile with:
// g++ sample.cpp -o sample $(Magick++-config --cppflags --cxxflags --ldflags --libs)
////////////////////////////////////////////////////////////////////////////////
#include <Magick++.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
using namespace Magick;
int main(int argc,char **argv)
{
InitializeMagick(*argv);
// Create an image object, scaled by a factor of 100 to speed it up !
float scale=100.0;
Image image("650x650","white");
// Construct drawing list
std::list<Magick::Drawable> drawList;
// Initial settings, blue lines 1 pixel thick
drawList.push_back(DrawableStrokeColor("blue"));
drawList.push_back(DrawableStrokeWidth(1));
// Read in lines from file, expected format "x1 y1 x2 y2"
int lineno=0;
std::ifstream infile("lines.txt");
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
int x1,y1,x2,y2;
iss >> x1;
iss >> y1;
iss >> x2;
iss >> y2;
x1 = int(x1/scale);
y1 = int(x2/scale);
x2 = int(y1/scale);
y2 = int(y2/scale);
cout << "Line: " << ++lineno << " " << x1 << "," << y1 << " " << x2 << "," << y2 << endl;
// Add this point to the list of lines to draw
drawList.push_back(DrawableLine(x1,y1,x2,y2));
}
// Draw everything using completed drawing list
image.draw(drawList);
// Write the image to a file
image.write( "result.png" );
return 0;
}
我用 Perl 生成了 1,000 行随机测试数据,如下所示:
perl -E 'for($i=0;$i<1000;$i++){printf("%d %d %d %d\n",int rand 65000,int rand 65000, int rand 65000, int rand 65000);}' > lines.txt
结果如下所示:
原答案
您也可以使用已安装在大多数 Linux 发行版上的 ImageMagick 轻松完成此操作。下面其实只有4行代码——剩下的都是注释:
#!/bin/bash
# Create the output image, 1000x1000 pixels say
convert -size 1000x1000 xc:pink result.png
# Suppressing lines that have a hash (#) at the start, read in the file "lines.txt"
grep -v "^#" lines.txt | while read x1 y1 x2 y2; do
echo Read line $x1,$y1 $x2,$y2
# Tell ImageMagick to draw the line on the image
convert result.png -stroke blue -strokewidth 5 -draw "line $x1,$y1 $x2,$y2" result.png
done
输出
Read line 123,567 798,900
Read line 788,900 87,89
您也可以使用 rsvg-convert
(来自 librsvg)或 svg2png
执行此操作。这两个程序都需要 SVG 格式的 inout 文件并将其呈现为 PNG 文件。所以你需要转换你的
123 567 798 900
788 900 87 89
喜欢这种东西
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<line x1="123" y1="567" x2="798" y2="900" stroke="blue" stroke-width="1"/>
<line x1="788" y1="900" x2="87" y2="89" stroke="blue" stroke-width="1"/>
</svg>
这可以通过像这样的 awk
脚本轻松完成:
awk '
BEGIN{ printf("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n") }
{
x1=; y1=; x2=; y2=;
printf("<line x1=\"" x1 "\" y1=\"" y1 "\" x2=\"" x2 "\" y2=\"" y2 "\" stroke=\"blue\" stroke-width=\"1\"/>\n")
}
END{ printf("</svg>\n") }' points.txt
然后您可以将其输出泵入我上面提到的两个程序中的任何一个:
awk ... | rsvg-convert -b \#ffff00 > result.png