Is it possible to use do loop inside multiplot in gnuplot? - loops

I need to create a figure with multiple subplots whereas in each subplot I need to plot multiple lines. Each line has to have a different color. (if every 30-40 lines the colors are iterated its ok for my purpose).
For example: ( I want 8 subplots)
set multiplot layout 2, 4
for the first subplot I can do the following
plot for [i=2:101] 'mydata.txt' u 1:i w line notitle lw 2
which will plot 100 lines inside the first subplot
plot for [i=1022:201] 'mydata.txt' u 1:i w line notitle lw 2
which adds another set of lines in the second panel etc.
The problem with this solution is that each separate line within the subplot gets not only a different color but also a different line style, some are solids some are dashed and each with different dash pattern etc.
Is there any way to use a unique line style e.g. all continuous lines and have different colors?
In the past I had found the following workaround, which works in the case of a single plot
rgb(r,g,b) = 65536 * int(r) + 256 * int(g) + int(b)
set multiplot
do for [i=2:201] {
rr = 255*rand(0)
gg = 255*rand(0)
bb = 255*rand(0)
plot 'moredata.inp' u 1:i:(rgb(rr,gg,bb)) w line notitle lt 1 lc rgb variable lw 2
}
However I cannot replace the "plot for [i=2:101]" with the do loop because the result is one line per subplot.
Any ideas?
Thank you

To use only solid lines, use
set termoption solid
In order to iterate over line colors, you can use lc variable (without the rgb!). In that case the last column is used as linetype index. If you want other colors of the linetypes you can use set linetype .... If you use set style increment user, the index refers to linestyles.
Or you can use lc palette and define an appropriate palette, see e.g. Gnuplot repeats colors in rowstack histograms. I think this might be the best option, because you need a lot of colors:
set palette model HSV defined ( 0 0 1 1, 1 1 1 1 ) # rainbow palette
plot for [i=2:101] 'mydata.txt' u 1:i lc palette frac (i/101.0) w line notitle

Related

How to plot 4d data into heatplot using gnuplot

plz help!
i have a dataset with the format of
x y z p
-0.574142 -0.818671 0.011756 0.000440
-0.364919 0.184603 0.912555 0.000324
-0.990822 -0.022168 0.133345 0.000419
-0.983317 -0.089955 0.158099 0.000417
-0.493497 0.474422 -0.728961 0.000501
-0.789287 -0.566719 0.236336 0.000413
0.293932 0.520691 -0.801551 0.000510
and they are random points on a 3d sphere, with the p value (the fourth column) representing the "heat" of that location, the actual datafile is with 50 such points.
i want to plot the surface of the sphere into a heatplot, not each point being colored.
i've searched for lots of post, all of them would require some kind of isoline, but in my case there isn't any. is it possible still using gnuplot to do heatmap? i'm also opened to any other way.
btw im running linux with newest gnuplot, the data are generated by c
ps: i understand theres a way of making data into isolines and then use gnuplot with pm3d, but i cant do that because all my x data is randomized, hence there is no isoline.
Note: This answer is only relevant to the newest gnuplot, version 5.4
Gnuplot version 5.4 can work in a 3D grid space of voxels, The voxel values can be used to hold a 4th dimension of data. I.e voxel(x,y,z) = value
This is a very new feature and could be improved, so your question serves as a nice example to show what it can and cannot do right now.
$data << EOD
x y z p
-0.574142 -0.818671 0.011756 0.000440
-0.364919 0.184603 0.912555 0.000324
-0.990822 -0.022168 0.133345 0.000419
-0.983317 -0.089955 0.158099 0.000417
-0.493497 0.474422 -0.728961 0.000501
-0.789287 -0.566719 0.236336 0.000413
0.293932 0.520691 -0.801551 0.000510
EOD
#
# Generate a heatmap on the surface of a sphere
#
set view equal xyz
set view 78, 246
set xyplane at 0
unset key
set xtics ("x" 0); set ytics ("y" 0); set ztics ("z" 1)
set hidden3d # only relevant to axis tics and labels
#
# Use spherical mapping to generate a set of points describing the surface.
# Then return to Cartesian coordinates to handle voxels.
#
set mapping spherical
set angle degrees
set samples 51
set isosamples 101
set urange [-90:90]
set vrange [0:360]
set table $surface
splot '++' using 1:2:(1.0) with points
unset table
set mapping cartesian
# define 100 x 100 x 100 voxel grid
rlow = -1.1; rhigh = 1.1
set xrange [rlow:rhigh]; set yrange [rlow:rhigh]; set zrange [rlow:rhigh]
set vgrid $vdensity size 100
vclear $vdensity
# mark voxels in a spherical region with radius <near> around each point in $data
# Note that values are summed rather than averaged
near = 0.1
vfill $data skip 1 using 1:2:3:(near):($4)
show vgrid
# color range should be found automatically but it isn't
set cbtics
set colorbox user origin screen 0.8, screen 0.2
set cbrange [ 0 : 0.001 ]
set palette cubehelix negative # colors from cbmin white -> cbmax dark
set pm3d depthorder
set pm3d lighting primary 0.4 specular 0.1
set title "Sphere surface is colored by the value of the nearest point[s] in $data"
splot $surface using 1:2:3:(voxel($1,$2,$3)) with pm3d

Matlab: Plot array such that each value has random shape and a color map

In Matlab:
How do I modify plot(x,y,'o'), where x=1:10 and y=ones(1,10), such that each point in the plot will have a random shape?
And how can I give it colors chosen from a scheme where the value at x=1 is the darkest blue, and x=10 is red (namely some sort of heat map)?
Can this be done without using loops? Perhaps I should replace "plot" with a different function for this purpose (like "scatter"? I don't know...)? The reason is that I am plotting this inside another loop, which is already very long, so I am interested in keeping the running-time short.
Thanks!
First, the plain code:
x = 1:20;
nx = numel(x);
y = ones(1, nx);
% Color map
cm = [linspace(0, 1, nx).' zeros(nx, 1) linspace(1, 0, nx).'];
% Possible markers
m = 'o+*.xsd^vph<>';
nm = numel(m);
figure(1);
hold on;
for k = 1:nx
plot(x(k), y(k), ...
'MarkerSize', 12, ...
'Marker', m(ceil(nm * (rand()))), ...
'MarkerFaceColor', cm(k, :), ...
'MarkerEdgeColor', cm(k, :) ...
);
end
hold off;
And, the output:
Most of this can be found in the MATLAB help for the plot command, at the Specify Line Width, Marker Size, and Marker Color section. Colormaps are simply n x 3 matrices with RGB values ranging from 0 to 1. So, I interpreted the darkest blue as [0 0 1], whereas plain red is [1 0 0]. Now, you just need a linear "interpolation" between those two for n values. Shuffling the marker type is done by simple rand. (One could generate some rand vector with size n beforehand, of course.) I'm not totally sure, if one can put all of these in one single plot command, but I'm highly sceptical. Thus, using a loop was the easiest way right now.

Opacity from RGB array

So I'm no expert in coding: I just have a vague understanding of a few bits and bobs.
I understand that images of pixel dimensions X*Y are stored in array of size 3*X*Y where each vector pulled from a given (x,y) value has 3 elements for the 3 RGB values.
I also understand that one can also store an image in a 4*X*Y array, where each pulled vector now has 4 values, RGBA with A being Alpha, used to represent the opacity of a particular pixel.
Now I'm into animation, and have pencil drawings of white clouds on a black background that I want to import into Flash. I would like the blacker parts of the drawing to be more transparent and the lighter parts to be more opaque. I have the scans of the drawings saved in .png format.
If I had any idea how to manipulate an image at the 'array level', I could have a stab at this myself but I'm at a loss.
I need a program that, given a .png image and a reference RGB value {a b c}, obtains the RGB array of the image and converts it into an RBGA array such that:
a pixel of RGB value {p q r}
...... Becomes ......
a pixel of RGBA value {p q r 1-M[(|p-a|^2 + |q-b|^2 + |r-c|^2)^1/2]}.
Where M is a normalisation factor which makes the largest alpha value = 1.
i.e. M = 1/[(255^2 + 255^2 + 255^2)^1/2]) = 0.0026411...
i.e. the alpha value of the replacement pixel is the 'distance' between the colour of the pixel and some reference colour which can be input.
This then needs to export the new RGBA Array as a png image.
Any ideas or any fellow animators know if this can be done directly with actionscript?
Example: Reference = {250 251 245}
RGB array =
|{250 251 245} {250 250 250}|
|{30 255 22} {234 250 0 }|
...... Becomes ......
RGBA array =
|{250 251 245 1} {250 251 245 0.987}|
|{30 255 22 0.173} {234 250 0 0.352}|
You can do this quite simply, just at the command-line, with ImageMagick which is installed on most Linux distros and is available for free on OSX and Windows.
The "secret sauce" is the -fx operator - described here.
So, let's generate a 300x200 black image and then use -fx to calculate the red channel so that the red varies across the image according to what fraction of the width (w) we are from the left side (i):
convert -size 300x200 xc:black -channel R -fx 'i/w' result.png
Note that I am generating an image "on-the-fly" with -size 300x200 xc:black, whereas if you have a PNG file with your animation frame in it, you can put that in, in its place.
Now let's say we want to vary the opacity/alpha too - according to the distance down the image from the top:
convert -size 300x200 xc:black -alpha on \
-channel R -fx 'i/w' \
-channel A -fx 'j/h' result.png
Ok, we are getting there... your function is a bit more complicated, so, rather than typing it on the command-line every time, we can put it in a script file called RGB2Opacity.fx like this:
convert -size 300x200 xc:black -alpha on -channel A -fx #RGB2Opacity.fx result.png
where RGB2Opacity.fx is simple and looks like this for the moment:
0.2
Now we need to put your "reference" pixel on the command line with your animation frame so that ImageMagick can work out the difference. That means your actual command-line will look more or less exactly like the following:
convert -size 300x200 xc:"rgb(250,251,245)" YourImage.png -alpha on -channel A -fx #RGB2Opacity.fx result.png
And then we need to implement your formula in the -fx script file. Your variable names must be at least 2 letters long with no digits in them, and you should return a single value for the opacity. Variables are all scaled between [0,1.0] so your 255 scaling is a little different. I have no sample image and I am not sure how the answer is supposed to look, but it will be pretty close to this:
MM=1/pow(3,0.5);
pmasq=pow((u.r-v.r),2.0);
qmbsq=pow((u.g-v.g),2.0);
rmcsq=pow((u.b-v.b),2.0);
1-MM*pow((pmasq+qmbsq+rmcsq),0.5)
I don't know if/how to put comments in -fx scripts, so I will explain the variable names below:
pmasq is the square of p minus a.
qmbsq is the square of q minus b.
rmcsq is the square of r minus c.
u.r refers to the red channel of the first image in ImageMagick's list, i.e. the red channel of your reference pixel.
v.g refers to the green channel of the second image in ImageMagick's list, i.e. the green channel of your animation frame.
Let's create your animation frame now:
convert xc:"rgb(250,251,245)" xc:"rgb(250,250,250)" xc:"rgb(30,255,22)" xc:"rgb(234,250,0)" +append frame.png
And check it looks correct:
convert frame.png txt:
Output
# ImageMagick pixel enumeration: 4,1,65535,srgb
0,0: (64250,64507,62965) #FAFBF5 srgb(250,251,245)
1,0: (64250,64250,64250) #FAFAFA grey98
2,0: (7710,65535,5654) #1EFF16 srgb(30,255,22)
3,0: (60138,64250,0) #EAFA00 srgb(234,250,0)
If we apply that to your image and check the results, you can see I have got it slightly wrong somewhere, butI'll leave you (or some other bright spark) to work that out...
convert -size 4x1 xc:"rgb(250,251,245)" frame.png -alpha on -channel A -fx #RGB2Opacity.fx result.png
convert result.png txt:
# ImageMagick pixel enumeration: 4,1,65535,srgba
0,0: (64250,64507,62965,65535) #FAFBF5FF srgba(250,251,245,1)
1,0: (64250,64507,62965,64764) #FAFBF5FC srgba(250,251,245,0.988235)
2,0: (64250,64507,62965,19018) #FAFBF54A srgba(250,251,245,0.290196)
3,0: (64250,64507,62965,29041) #FAFBF571 srgba(250,251,245,0.443137)

Why there is always some noise in the rendered text of freetype?

I'm writing a opengl program that use freetype2 as text rendering engine.
Using its LCD subpixel rendering, I found that there are always some noise pixels in the rendered result, why is that happening? Besides, although it's manual says that the LCD mode will generate buffer with width a multiple of 3, I often found the width to be 3n+1 or 3n+2, and inconsistent with the face->glyph->bitmap->width.
Actually, after hours of trying and testing, I realized that the rasterized glyph data has some non-relevant bytes called padding. Illustratively, imaging below is a glyph data in a buffer: (o/x are meaningful data, while . are non-relevant)
0 1 2 3 4 5 6 7
0 o x o x o x . .
1 x o x o x o . .
2 o x o x o x . .
3 x o x o x o . .
4 o x o x o x . .
There are three numbers describing the size of this buffer, the first two are obvious:
rows = 5 //since there are 5 rows
width = 6 //since each row has 6 bytes of data
However, there is actually a third one:
pitch = 8 //the actual width of rows, including "padding"
If you ignore this property of buffer like me, and got the wrong idea that the width is the actual width, you'll be rendering a distorted or translated glyph shape.
My understanding of this 'padding' is like Dhaivat Pandya has said, it's a compensation. However, it's not a compensation for parity, (obviously +2 is not changing parity,) by default it's a compensation to make the actual width a multiple of 4. But yes, you can change the 4 into 2 or even 1. I guess by forming a data matrix with its width a multiple of 4, it can be loaded faster, for example, to be loaded in longint instead of byte.
But still, the insightfulness of R.. really impressed me. I think you guys just can't image I could make such a basic mistake.
I've never used FreeType library, so I can't talk by personal experience, but maybe that "noise" is because your text width or your calculation of the top-left text coordinate is off by one?

creating a legend within for loop for Matlab plot

I want to plot several curves, each having a different length. So, I've placed each curve as an array in a cell index, Y (this allows me to index through arrays of different sizes inside a FOR loop). I use "hold all" below to enable each iteration of the FOR loop to plot each new array in the cell array Y inside the same plot.
hold all;
for i = 1:1:length(maxusers)
time = increment*(0:1:length(Y{i})-1);
plot(time,Y{i,1,:});
end
While the use of a cell array here does simplify plotting the various curves inside Y, the problem I'm having is creating legend. Currently I'm using a really long/ugly switch statement to cover every possible scenario, but I think there should be a more elegant solution.
If I have an array (where maxusers=4, for example) that is:
filesize = [10 100 200 300];
I know the legend Matlab command that works is:
legend(num2str(filesize(1)),num2str(filesize(2)),num2str(filesize(3)),num2str(filesize(4)));
but I get stuck trying to create a legend command when the number of curves is a variable given by maxusers. Any ideas? Thanks in advance.
Try this:
>> filesize = [10 100 200 300];
>> str = strtrim(cellstr(int2str(filesize.'))) %'# Create a cell array of
%# strings
str =
'10'
'100'
'200'
'300'
>> legend(str{:}); %# Pass the cell array contents to legend
%# as a comma-separated list

Resources