Plotting Heatmap with different column/line widths

不问归期 提交于 2021-02-16 14:45:17

问题


I am simulating something and want to figure out the influence of two parameters. Therefore I vary them both and look for the result on each pair of parameter values and get a result like:

  0  1000  2000  3000  4000  5000  ....
0  13.2  14.8  19.9  25.5  27.3 ...
1000  21.3  25.9  32.3 etc.
2000  etc.
3000
4000
....

To visualize them, I use gnuplot, creating a heatmap, which works perfectly fine, showing me colors and height:

reset 

set terminal qt

set title "Test"
unset key
set tic scale 0

set palette rgbformula 7,5,15
set cbrange [0:100]
set cblabel "Transmission"

set pm3d at s interpolate 1,1

unset surf

set xlabel "U_{Lense} [V]"
set ylabel "E_{Start} [eV]"

set datafile separator "\t"
splot "UT500test.csv" matrix rowheaders columnheaders

Now I want to look more detailed on some areas on my heatmap, and vary my parameters in steps of 100 difference, not 1000 as shown in the table above. But because the simulation takes quite a long time, I just do this for some areas, so my table looks like this:

0  1000  2000  2100  2200  2300  2400 ...  2900  3000  4000  ...
...

Now I want to show this in the heatmap, too. But everytime I tried this, all the bins on the heatmap, no matter if 1000 or 100 difference are of the same width. But I want the ones with 100 difference to be only 1/10 of the width of the 1000 differences. Is there a possibility to do this?


回答1:


You could do something with plotting style with boxxyerror. It's pretty straightforward, except the way to get the x-coordinates into an array which will be used later during plotting. Maybe, there are smarter solutions.

Code:

### heatmap with irregular spacing
reset session
unset key 

$Data <<EOD
0.00    0.00    1000    2000    2100    2200    2300    2400    3000    4000
1000    0.75    0.75    0.43    0.34    0.61    0.74    0.66    0.97    0.58
1100    0.82    0.90    0.18    0.12    0.87    0.15    0.01    0.57    0.97
1200    0.10    0.15    0.68    0.73    0.55    0.07    0.98    0.89    0.01
1300    0.67    0.38    0.41    0.85    0.37    0.45    0.49    0.21    0.98
1400    0.76    0.53    0.68    0.09    0.22    0.40    0.59    0.33    0.08
2000    0.37    0.32    0.30    NaN     0.33    NaN     0.73    0.94    0.96
3000    0.07    0.61    0.37    0.54    0.32    0.28    0.62    0.51    0.48
4000    0.79    0.98    0.78    0.06    0.16    0.45    0.83    0.50    0.10
5000    0.49    0.95    0.29    0.59    0.55    0.88    0.29    0.47    0.93
EOD

stats $Data nooutput
BoxHalfWidth=50
# put first row into array
array ArrayX[STATS_columns]
set table $Dummy
    plot for [i=1:STATS_columns] $Data u (ArrayX[i]=column(i)) every ::0::0 with table
unset table

plot for [i=2:STATS_columns] $Data u (ArrayX[i]):1:(BoxHalfWidth):(BoxHalfWidth):i every ::1 with boxxyerror fs solid 1.0 palette
### end of code

Result:

Edit:

With a little bit more effort you can as well generate a plot which covers the whole area. In contrast to the simpler code from @Ethan, the recangles are centered on the datapoint coordinates and have the color of the actual datapoint z-value. Furthermore, the datapoint (2200,2000) is also plotted. The borders of the rectangles are halfway between matrix points. The outer rectangles have dimensions equal to the x and y distance to the next inner matrix point.

Code:

### heatmap with irregular spacing with filled area
reset session
unset key 

$Data <<EOD
0.00    0.00    1000    2000    2100    2200    2300    2400    3000    4000
1000    0.75    0.75    0.43    0.34    0.61    0.74    0.66    0.97    0.58
1100    0.82    0.90    0.18    0.12    0.87    0.15    0.01    0.57    0.97
1200    0.10    0.15    0.68    0.73    0.55    0.07    0.98    0.89    0.01
1300    0.67    0.38    0.41    0.85    0.37    0.45    0.49    0.21    0.98
1400    0.76    0.53    0.68    0.09    0.22    0.40    0.59    0.33    0.08
2000    0.37    0.32    0.30    NaN     0.33    NaN     0.73    0.94    0.96
3000    0.07    0.61    0.37    0.54    0.32    0.28    0.62    0.51    0.48
4000    0.79    0.98    0.78    0.06    0.16    0.45    0.83    0.50    0.10
5000    0.49    0.95    0.29    0.59    0.55    0.88    0.29    0.47    0.93
EOD

stats $Data nooutput
ColCount = STATS_columns-1
RowCount = STATS_records-1
# put first row and column into arrays
array ArrX[ColCount]
array ArrY[RowCount]
set table $Dummy
    plot for [i=1:ColCount] $Data u (ArrX[i]=column(i+1)) every ::0::0 with table
    plot $Data u (ArrY[$0+1]=$1) every ::1 with table
unset table

dx(i) = (ArrX[i]-ArrX[i-1])*0.5
dy(i) = (ArrY[i]-ArrY[i-1])*0.5
ndx(i,j) = ArrX[i] - (i-1<1        ? dx(i+1) : dx(i))
pdx(i,j) = ArrX[i] + (i+1>ColCount ? dx(i)   : dx(i+1))
ndy(i,j) = ArrY[j] - (j-1<1        ? dy(j+1) : dy(j))
pdy(i,j) = ArrY[j] + (j+1>RowCount ? dy(j)   : dy(j+1))

set xrange[ndx(1,1):pdx(ColCount,1)]
set yrange[ndy(1,1):pdy(1,RowCount)]
set tic out
plot for [i=2:STATS_columns] $Data u (ArrX[i-1]):1:(ndx(i-1,$0)):(pdx(i-1,$0)): \
    (ndy(i-1,$0+1)):(pdy(i-1,$0+1)):i every ::1 with boxxyerror fs solid 1.0 palette
### end of code

Result:

Edit2: Just for fun, here is the "retro-version" for gnuplot 5.0:

gnuplot5.0 does not support arrays. Although, gnuplot5.0 supports datablocks, but apparently indexing like $Datablock[1] does not work. So, the workaround-around is to put the matrix X,Y coordinates into strings CoordsX and CoordsY and get the coordinates with word(). If there is not another limitation with string and word(), the following worked with gnuplot5.0 and gave the same result as above.

Code:

### heatmap with irregular spacing with filled area
# compatible with gnuplot 5.0
reset session
unset key 

$Data <<EOD
0.00    0.00    1000    2000    2100    2200    2300    2400    3000    4000
1000    0.75    0.75    0.43    0.34    0.61    0.74    0.66    0.97    0.58
1100    0.82    0.90    0.18    0.12    0.87    0.15    0.01    0.57    0.97
1200    0.10    0.15    0.68    0.73    0.55    0.07    0.98    0.89    0.01
1300    0.67    0.38    0.41    0.85    0.37    0.45    0.49    0.21    0.98
1400    0.76    0.53    0.68    0.09    0.22    0.40    0.59    0.33    0.08
2000    0.37    0.32    0.30    NaN     0.33    NaN     0.73    0.94    0.96
3000    0.07    0.61    0.37    0.54    0.32    0.28    0.62    0.51    0.48
4000    0.79    0.98    0.78    0.06    0.16    0.45    0.83    0.50    0.10
5000    0.49    0.95    0.29    0.59    0.55    0.88    0.29    0.47    0.93
EOD

stats $Data nooutput
ColCount = int(STATS_columns-1)
RowCount = int(STATS_records-1)
# put first row and column into arrays

CoordsX = ""
set table $Dummy
    set xrange[0:1]     # to avoid warnings
    do for [i=2:ColCount+1] {
        plot $Data u (Value=column(i)) every ::0::0 with table
        CoordsX = CoordsX.sprintf("%g",Value)." "
    }
unset table
CoordsY = ""
set table $Dummy
    do for [i=1:RowCount] {
        plot $Data u (Value=$1) every ::i::i with table
        CoordsY= CoordsY.sprintf("%g",Value)." "
    }
unset table

dx(i) = (word(CoordsX,i)-word(CoordsX,i-1))*0.5
dy(i) = (word(CoordsY,i)-word(CoordsY,i-1))*0.5
ndx(i,j) = word(CoordsX,i) - (i-1<1        ? dx(i+1) : dx(i))
pdx(i,j) = word(CoordsX,i) + (i+1>ColCount ? dx(i)   : dx(i+1))
ndy(i,j) = word(CoordsY,j) - (j-1<1        ? dy(j+1) : dy(j))
pdy(i,j) = word(CoordsY,j) + (j+1>RowCount ? dy(j)   : dy(j+1))

set xrange[ndx(1,1):pdx(ColCount,1)]
set yrange[ndy(1,1):pdy(1,RowCount)]
set tic out
plot for [i=2:ColCount+1] $Data u (real(word(CoordsX,i-1))):1:(ndx(i-1,int($0))):(pdx(i-1,int($0))): \
    (ndy(i-1,int($0+1))):(pdy(i-1,int($0+1))):i every ::1 with boxxyerror fs solid 1.0 palette
### end of code



回答2:


The extra steps with stats are not necessary. You can access the true coordinates directly as a nonuniform matrix:

  set offset 100,100,100,100
  plot $Data matrix nonuniform using 1:2:3 with points pt 5 lc palette

The missing piece is to fill in the full area rather than plotting single points. You can do this using pm3d:

  set pm3d corners2color mean
  set view map
  splot $Data matrix nonuniform with pm3d

The colors do not match the previous plot because pm3d considers all 4 corners of each box when assigning a color. I told it to take the mean value (that's the default) but many other variants are possible. You could smooth the coloring further with set pm3d interpolate 3,3



来源:https://stackoverflow.com/questions/56035321/plotting-heatmap-with-different-column-line-widths

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!