gnuplot等高线图阴影线 [英] gnuplot contour plot hatched lines

查看:253
本文介绍了gnuplot等高线图阴影线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用gnuplot绘制多个函数的轮廓图。这是为了优化问题。
我有3个函数:


  1. f(x,y)

  2. g1(x,y)

  3. g2(x ,y)

g1(x,y) g2(x,y)是约束,并且希望在 f(x,y)



以下是教科书示例:





由于@theozh,这是我尝试在gnuplot中复制它。

  ###带标签的轮廓线
重置会话

f(x,y)=(x ** 2 + y-11)** 2+ (x + y ** 2-7)** 2
g1(x,y)=(x-5)** 2 + y ** 2
g2(x,y)= 4 * x + y

设置xrange [0:6]
设置yrange [0:6]
设置isosample 250,250
设置
$之外的键b $ b设置轮廓基准
设置cntrparam水平圆盘10,30,75,150,300,500,850,1500
未设置面
设置表$ Contourf
点图f(x,y)
未设置表

设置轮廓基准
设置cntrparam水平光盘26
Unset surface
set table $ Contourg1
splot g1(x,y)
unset table

set outline base
set cntrparam level disc 20
未设置表面
设置表$ Contourg2
点g2(x,y)
未设置表

设置样式文本框不透明边框

设置数据文件注释char
图,用于[i = 1:8] $ Contourf u 1:2:(i)跳过5索引i-1 wl lw 1.5 lc var title columnheader(5)
replot $ Contourg1 u 1:2:(1)跳过5索引0 wl lw 4 lc 0标题columnheader(5)
replot $ Contourg2 u 1:2:(1)跳过5索引0 wl lw 4 lc 0标题columnheader(5 )



我想在gnuplot示例中复制教科书图片。如何在函数 g1 g2 (上图中的黑色粗线)上做阴影标记。



@theozh提供了以下出色的解决方案。但是,该方法不适用于陡峭曲线。

 重置会话
未设置键

设置大小平方

g(x,y)= -0.8-1 / x ** 3 + y

设置xrange [0:4]
设置yrange [0:4]
设置isosample 250,250
设置键

设置轮廓基础
取消设置表面

设置cntrparam水平光盘0
设置表$ Contourg
图g(x,y)
未设置表格

设置角度度
设置数据文件commentschar

图$ Contourg u 1:2跳过5索引0 wl lw 2 lc 0标题columnheader(5)

设置样式填充透明模式4
重新绘制$ Contourg u 1:2:($ 2 + 0.2)跳过5索引0 w filledcurves lc 0无标题

得出下图。有没有一种方法可以使用不同的偏移量,例如x小于x的偏移量x值。 1.3和x> 1.3偏移y值。这将产生更好的填充曲线。可以在这里找到我所寻找的Matlab实现:



在拒绝@Ethans程序中,我得到以下信息,与@Ethan相比,dashtype相对较粗,不知道为什么,我使用的是gnuplot v5 .2和wxt终端。



解决方案

我不知道gnuplot中的功能会生成这样的阴影线。
一种解决方法如下:将曲线稍微移动一些值,并用填充曲线和填充图案填充。但是,这仅在曲线为直线或弯曲不太多时才有效。
不幸的是,gnuplot中的填充图案也非常有限(请参阅



添加:



使用gnuplot可能大多数时候都可以找到解决方法。您可以让它变得多么复杂或丑陋。
对于这种陡峭的功能,请使用以下技巧。基本思想很简单:将原始曲线和已移动的曲线合并,将这两条曲线合并并填充为实线。但是您必须反转其中一条曲线(类似于我之前已经描述的曲线:



加法2:



实际上,我喜欢@E而不是创建额外的水平轮廓线的方法。只要梯度不太大,此效果就很好。否则,第二轮廓线可能会出现明显的变形(请参见下面的红色曲线)。但是,在上面的 g1 g2 的示例中,您不会发现任何区别。另一优点是剖面线垂直于曲线。缺点是您可能会打断常规模式。



原始曲线在x和/或y处有少量偏移并填充区域的解决方案不会



下面,黑色阴影曲线是这些方法的组合。



步骤:


  1. 创建一条轮廓线

  2. 创建扩展(ext)或平移( shf)等高线(通过新的等高线值或通过移动现有等高线值)

  3. 命令等高线(ord)

  4. 反转等高线(rev)

  5. 添加有序(ord)和扩展,有序,反向(extordrev)

  6. 用以下命令绘制添加的轮廓线(add) filledcuves

注意:如果要将轮廓线移动x, y您必须先订购然后转移它,否则宏 @ContourOrder 不能再订购它。



您看见 会变得复杂。总而言之,到目前为止,有三种方法:



(a)超水平轮廓线和粗虚线(@Ethan)



专业版:简称,适用于振荡和闭合曲线;
con:如果大梯度会变坏



(b) x,y偏移轮廓线并阴影fillcurves(@theozh)



pro:几个参数,清晰的图片;
con :冗长,只有4种填充图案)



(c)数据点的派生( @Dan Sp。)



专业版:可能为倾斜的填充图案具有灵活性;
con:是否需要导数(如果没有函数,则为数字),模式取决于比例



黑色曲线实际上是(a)和(b)的混合。
蓝色曲线是(b)。 (a)和(b)在红色曲线上均无法正常工作。也许(c)?
您可能会考虑进一步混合使用这些方法...但这可能还会很长。



代码:

  ###具有散边的轮廓线
设置项wxt对接
重置会话

f (x,y)=(x ** 2 + y-11)** 2+(x + y ** 2-7)** 2
g1(x,y)=(x-5)* * 2 + y ** 2
g2(x,y)= 4 * x + y
g3(x,y)= -0.8-1 / x ** 3 + y

设置xrange [0:6]
设置yrange [0:6]
设置isosample 250,250
设置$外部的键

设置轮廓基础
未设置表面

设置cntrparam水平光盘10,30,75,150,300,500,850,1500
设置表$ Contourf
曲线f(x,y)
未设置表

设置cntrparam级别光盘26
设置表$ Contourg1
点g1(x,y)
未设置表

设置cntrparam级别光盘20
设置表$ Contourg2
曲线g2(x,y)
未设置表

设置cntrparam级别光盘0
设置表$ Contourg3
曲线g3(x,y)
未设置表格


#创建一些多余的东西t轮廓线
#宏用于设置轮廓线
ContourCreate =’\
set cntrparam level光盘Level; \
设置表@Output; \
散点@Input; \
未设置表'

级别= 27.5
输入='g1(x,y)'
输出='$ Contourg1_ext'
@ContourCreate

等级= 20.5
输入='g2(x,y)'
输出='$ Contourg2_ext'
@ContourCreate

等级= 10
输入='f(x,y)'
输出='$ Contourf0'
@ContourCreate

级别= 13
输入=' f(x,y)'
输出='$ Contourf0_ext'
@ContourCreate


#用于对轮廓线的数据点进行排序的宏b $ b ContourOrder ='\
统计@DataIn跳过6无输出; \
N = STATS_blank-1; \
设置表@DataOut; \
为[i = N:0:-1]做{图@DataIn u 1:2使用表将每个::: i :: i跳过5个索引0}; \
未设置表'

DataIn ='$ Contourg1'
DataOut ='$ Contourg1_ord'
@ContourOrder

DataIn =' $ Contourg1_ext'
DataOut ='$ Contourg1_extord'
@ContourOrder

DataIn ='$ Contourg2'
DataOut ='$ Contourg2_ord'
@ContourOrder

DataIn ='$ Contourg2_ext'
DataOut ='$ Contourg2_extord'
@ContourOrder

DataIn ='$ Contourg3'
DataOut =' $ Contourg3_ord'
@ContourOrder

设置表$ Contourg3_ordshf
图$ Contourg3_ord u($ 1 + 0.15):($ 2 + 0.15)w table#移动曲线
未设置表

DataIn ='$ Contourf0'
DataOut ='$ Contourf0_ord'
@ContourOrder

DataIn ='$ Contourf0_ext'
DataOut ='$ Contourf0_extord'
@ContourOrder

#用于反转数据块的宏
ContourReverse ='\
set print @DataOut; \
做[i = | @DataIn |:1:-1] {print @DataIn [i]}; \
set print'

DataIn ='$ Contourg1_extord'
DataOut ='$ Contourg1_extordrev'
@ContourReverse

DataIn =' $ Contourg2_extord'
DataOut ='$ Contourg2_extordrev'
@ContourReverse

DataIn ='$ Contourg3_ordshf'
DataOut ='$ Contourg3_ordshfrev'
@ContourReverse

DataIn ='$ Contourf0_extord'
DataOut ='$ Contourf0_extordrev'
@ContourReverse

#用于添加数据块的宏
ContourAdd ='\ \
set print @DataOut; \
为[i = | @ DataIn1 | :: 1:-1]做{打印@ DataIn1 [i]}; \
为[i = | @ DataIn2 | :: 1:-1]做{打印@ DataIn2 [i]}; \
set print'

DataIn1 ='$ Contourg1_ord'
DataIn2 ='$ Contourg1_extordrev'
DataOut ='$ Contourg1_add'
@ContourAdd

DataIn1 ='$ Contourg2_ord'
DataIn2 ='$ Contourg2_extordrev'
DataOut ='$ Contourg2_add'
@ContourAdd

DataIn1 =' $ Contourg3_ord'
DataIn2 ='$ Contourg3_ordshfrev'
DataOut ='$ Contourg3_add'
@ContourAdd

DataIn1 ='$ Contourf0_ord'
DataIn2 =' $ Contourf0_extordrev'
DataOut ='$ Contourf0_add'
@ContourAdd

设置样式填充noborder
设置数据文件注释char
图\
表示[i = 1:8] $ Contourf u 1:2:(i)跳过5索引i-1 wl lw 1.5 lc var title columnheader(5),\
$ Contourg1 u 1:2跳过5索引0 wl lw 3 lc 0标题columnheader(5),\
$ Contourg2 u 1:2跳过5索引0 wl lw 3 lc 0标题columnheader(5),\
$ Contourg3 u 1 :2跳过5索引0 wl lw 3 lc 0标题columnheader(5),\
$ Contourg1_add u 1:2 w filledcurves fs tran透明模式4 lc rgb黑色无标题,\
$ Contourg2_add u 1:2 w filledcurves fs透明模式5 lc rgb black无标题,\
$ Contourg3_add u 1:2 w filledcurves fs透明模式5 lc rgb blue标题,\
$ Contourf0_add u 1:2 w filledcurves fs透明模式6 lc rgb red标题,\
###代码结尾

结果:





添加3:



如果用 filledcurves 画一条线,我想gnuplot会将第一个点和最后一个点用一条直线连接起来并填充封闭区域。
在您的圆形/椭圆形示例中,外部曲线在图形的顶部边界处被剪切。我想这就是该脚本在这种情况下不起作用的原因。您必须标识外部曲线的起点和终点,并排列连接的曲线,以使这些点成为起点和终点。
您会发现它变得越来越复杂...



以下内容应说明其工作方式:在起点处绘制一条曲线,例如将内部曲线从点1到100,然后再次添加内部曲线的点1,继续将外部曲线的点1(方向相反)继续到点100,然后再次添加外部曲线的点1。然后,gnuplot通过将外部曲线的点1与内部曲线的点1连接来闭合曲线。然后将其绘制为填充图案。





如果您将函数 g1(x,y)更改为 g1(x,y)= x * y / 2 +( x + 2)** 2+(y-1.5)** 2 / 2-2
(请注意差异 y-1.5 而不是 y-2 ),一切正常。见下文。



代码:

  ###在封闭的线上孵化
重置会话

f(x,y)= x * exp(-x ** 2-y ** 2)+(x ** 2 + y ** 2)/ 20
g1(x,y)= x * y / 2 +(x + 2)** 2+(y-1.5)** 2 / 2-2

设置xrange [-7:7]
设置yrange [-7:7]
设置isosample 250、250
设置键在
之外
设置轮廓基本
未设置表面

设置cntrparam水平圆盘4,3.5,3,2.5,2,1.5,1,0.5,0
设置表$ Contourf
曲线f (x,y)
未设置表

设置cntrparam级别光盘0
设置表$ Contourg1
点g1(x,y)
未设置表

#创建一些额外的偏移轮廓线
#宏用于设置轮廓线
ContourCreate ='\
set cntrparam level光盘Level; \
设置表@Output; \
散点@Input; \
未设置表'

级别= 1
输入='g1(x,y)'
输出='$ Contourg1_ext'
@ContourCreate

#用于对轮廓线的数据点进行排序的宏,可以将其拆分
ContourOrder ='\
stats @DataIn skip 6 nooutput; \
N = STATS_blank-1; \
设置表@DataOut; \
为[i = N:0:-1]做{图@DataIn u 1:2使用表将每个::: i :: i跳过5个索引0}; \
未设置表'

DataIn ='$ Contourg1'
DataOut ='$ Contourg1_ord'
@ContourOrder

DataIn =' $ Contourg1_ext'
DataOut ='$ Contourg1_extord'
@ContourOrder

#用于反转数据块的宏
ContourReverse ='\
set print @DataOut ; \
做[i = | @DataIn |:1:-1] {print @DataIn [i]}; \
set print'

DataIn ='$ Contourg1_extord'
DataOut ='$ Contourg1_extordrev'
@ContourReverse

#宏用于添加数据块
ContourAdd ='\
set print @DataOut; \
为[i = | @ DataIn1 | :: 1:-1]做{打印@ DataIn1 [i]}; \
为[i = | @ DataIn2 | :: 1:-1]做{打印@ DataIn2 [i]}; \
set print'

DataIn2 ='$ Contourg1_ord'
DataIn1 ='$ Contourg1_extordrev'
DataOut ='$ Contourg1_add'
@ContourAdd

设置样式填充边框
设置数据文件注释char
图plot
表示[i = 1:8] $ Contourf u 1:2:(i)跳过5索引i-1 wl lw 1.5 lc var标题columnheader(5),\
$ Contourg1 u 1:2跳过5索引0 wl lw 2 lc 0标题columnheader(5),\
$ Contourg1_add u 1:2 w Filledcurves fs透明模式5 lc rgb black notitle
###代码结尾

结果:




I'm using gnuplot for contour plot of a several function. This is for optimization problem. I have 3 functions:

  1. f(x,y)
  2. g1(x,y)
  3. g2(x,y)

both g1(x,y) and g2(x,y) are constraints and would like to plot on top of the contour plot of f(x,y).

Here is the textbook example:

Here is my attempt to replicate it in gnuplot, thanks to @theozh.

### contour lines with labels
reset session

f(x,y)=(x**2+y-11)**2+(x+y**2-7)**2
g1(x,y)=(x-5)**2+y**2
g2(x,y) = 4*x+y

set xrange [0:6]
set yrange [0:6]
set isosample 250, 250
set key outside

set contour base
set cntrparam levels disc 10,30,75,150,300,500,850,1500 
unset surface
set table $Contourf
    splot f(x,y)
unset table

set contour base
set cntrparam levels disc 26
unset surface
set table $Contourg1
    splot g1(x,y)
unset table

set contour base
set cntrparam levels disc 20
unset surface
set table $Contourg2
    splot g2(x,y)
unset table

set style textbox opaque noborder

set datafile commentschar " "
plot for [i=1:8] $Contourf u 1:2:(i) skip 5 index i-1 w l lw 1.5 lc var title columnheader(5)
replot $Contourg1 u 1:2:(1) skip 5 index 0 w l lw 4 lc 0 title columnheader(5)
replot $Contourg2 u 1:2:(1) skip 5 index 0 w l lw 4 lc 0 title columnheader(5)

I would like to replicate the textbook picture in the gnuplot example. How to do a hatch mark on the functions g1 and g2, the thick black line in plot above.

@theozh provided an excellent solution below. However, the method doesnot work for steep curves. As an example

reset session
unset key

set size square

g(x,y) = -0.8-1/x**3+y

set xrange [0:4]
set yrange [0:4]
set isosample 250, 250
set key off

set contour base
unset surface

set cntrparam levels disc 0
set table $Contourg
    splot g(x,y)
unset table

set angle degree
set datafile commentschar " "

plot $Contourg u 1:2 skip 5 index 0 w l lw 2 lc 0 title columnheader(5)

set style fill transparent pattern 4
replot $Contourg u 1:2:($2+0.2) skip 5 index 0 w filledcurves lc 0 notitle 

yields the following figure. Is there a way to use different offsets, for example offset x values for x < 1.3 and for x > 1.3 offset y values. This would yield a much better filled curve. A matlab implementations of what I was looking for can be found here: https://www.mathworks.com/matlabcentral/fileexchange/29121-hatched-lines-and-contours.

In replcating @Ethans program, I get the following, the dashtype is relatively thick compared to @Ethan not sure why, I'm using gnuplot v5.2 and wxt terminal.

When I replicate @theozh code, it works very well except for closed contours, not sure why? see below for example:

f(x,y)=x*exp(-x**2-y**2)+(x**2+y**2)/20
g1(x,y)= x*y/2+(x+2)**2+(y-2)**2/2-2

set xrange [-7:7]
set yrange [-7:7]
set isosample 250, 250
set key outside

set contour base
unset surface

set cntrparam levels disc 4,3.5,3,2.5,2,1.5,1,0.5,0 
set table $Contourf
    splot f(x,y)
unset table

set cntrparam levels disc 0
set table $Contourg1
    splot g1(x,y)
unset table

# create some extra offset contour lines
# macro for setting contour lines
ContourCreate = '\
    set cntrparam levels disc Level; \
    set table @Output; \
        splot @Input; \
    unset table'

Level = 0.45
Input = 'g1(x,y)'
Output = '$Contourg1_ext'
@ContourCreate


# Macro for ordering the datapoints of the contour lines which might be split
ContourOrder = '\
stats @DataIn skip 6 nooutput; \
N = STATS_blank-1; \
set table @DataOut; \
    do for [i=N:0:-1] { plot @DataIn u 1:2 skip 5 index 0 every :::i::i with table }; \
unset table'

DataIn = '$Contourg1'
DataOut = '$Contourg1_ord'
@ContourOrder

DataIn = '$Contourg1_ext'
DataOut = '$Contourg1_extord'
@ContourOrder


# Macro for reversing a datablock
ContourReverse = '\
set print @DataOut; \
    do for [i=|@DataIn|:1:-1] { print @DataIn[i]}; \
set print'

DataIn = '$Contourg1_extord'
DataOut = '$Contourg1_extordrev'
@ContourReverse

# Macro for adding datablocks
ContourAdd = '\
set print @DataOut; \
    do for [i=|@DataIn1|:1:-1] { print @DataIn1[i]}; \
    do for [i=|@DataIn2|:1:-1] { print @DataIn2[i]}; \
set print'

DataIn1 = '$Contourg1_ord'
DataIn2 = '$Contourg1_extordrev'
DataOut = '$Contourg1_add'
@ContourAdd


set style fill noborder 
set datafile commentschar " "
plot \
    for [i=1:8] $Contourf u 1:2:(i) skip 5 index i-1 w l lw 1.5 lc var title columnheader(5), \
    $Contourg1 u 1:2 skip 5 index 0 w l lw 2 lc 0 title columnheader(5), \
    $Contourg1_add u 1:2 w filledcurves fs transparent pattern 5 lc rgb "black" notitle

解决方案

I'm not aware of a feature in gnuplot which would generate such hatched lines. One workaround could be the following: shift your curves slightly by some value and fill it with filledcurves and a hatch pattern. However, this works only well if the curve is a straight line or not too much bent. Unfortunately, there is also only a very limited number of hatch patterns in gnuplot (see Hatch patterns in gnuplot) and they are not customizable. You need to play with the shift value and the hatched fill pattern.

Code:

### contour lines with hatched side
reset session

f(x,y)=(x**2+y-11)**2+(x+y**2-7)**2
g1(x,y)=(x-5)**2+y**2
g2(x,y) = 4*x+y

set xrange [0:6]
set yrange [0:6]
set isosample 250, 250
set key outside

set contour base
unset surface

set cntrparam levels disc 10,30,75,150,300,500,850,1500 
set table $Contourf
    splot f(x,y)
unset table

set cntrparam levels disc 26
set table $Contourg1
    splot g1(x,y)
unset table

set cntrparam levels disc 20
set table $Contourg2
    splot g2(x,y)
unset table
set angle degree
set datafile commentschar " "
plot for [i=1:8] $Contourf u 1:2:(i) skip 5 index i-1 w l lw 1.5 lc var title columnheader(5)
replot $Contourg1 u 1:2 skip 5 index 0 w l lw 4 lc 0 title columnheader(5)
replot $Contourg2 u 1:2 skip 5 index 0 w l lw 4 lc 0 title columnheader(5)

set style fill transparent pattern 5
replot $Contourg1 u 1:2:($2+0.2) skip 5 index 0 w filledcurves lc 0 notitle
set style fill transparent pattern 4
replot $Contourg2 u 1:2:($2+0.5) skip 5 index 0 w filledcurves lc 0 notitle
### end of code

Result:

Addition:

With gnuplot you will probably find a workaround most of the times. It's just a matter how complicated or ugly you allow it to become. For such steep functions use the following "trick". The basic idea is simple: take the original curve and the shifted one and combine these two curves and plot them as filled. But you have to reverse one of the curves (similar to what I already described earlier: https://stackoverflow.com/a/53769446/7295599).

However, here, a new "problem" arises. For whatever reason, the contour line data consist out of several blocks separated by an empty line and it's not a continous sequence in x. I don't know why but that's the contour lines gnuplot creates. To get the order right, plot the data into a new datablock $ContourgOnePiece starting from the last block (every :::N::N)to the first block (every :::0::0). Determine the number of these "blocks" by stats $Contourg and STATS_blank. Do the same thing for the shifted contour line into $ContourgShiftedOnePiece. Then combine the two datablocks by printing them line by line to a new datablock $ClosedCurveHatchArea, where you actually reverse one of them. This procedure will work OK for strictly monotonous curves, but I guess you will get problems with oscillating or closed curves. But I guess there might be also some other weird workarounds. I admit, this is not a "clean" and "robust" solution, but it somehow works.

Code:

### lines with one hatched side
reset session
set size square

g(x,y) = -0.8-1/x**3+y

set xrange [0:4]
set yrange [0:4]
set isosample 250, 250
set key off

set contour base
unset surface

set cntrparam levels disc 0
set table $Contourg
    splot g(x,y)
unset table

set angle degree
set datafile commentschar " "

# determine how many pieces $Contourg has
stats $Contourg skip 6 nooutput  # skip 6 lines
N = STATS_blank-1                # number of empty lines

set table $ContourgOnePiece
    do for [i=N:0:-1] {
        plot $Contourg u 1:2 skip 5 index 0 every :::i::i with table
    }
unset table
# do the same thing with the shifted $Contourg
set table $ContourgShiftedOnePiece
    do for [i=N:0:-1] {
        plot $Contourg u ($1+0.1):($2+0.1):2 skip 5 index 0 every :::i::i with table
    }
unset table
# add the two curves but reverse the second of them
set print $ClosedCurveHatchArea append
    do for [i=1:|$ContourgOnePiece|:1] {
        print $ContourgOnePiece[i]
    }
    do for [i=|$ContourgShiftedOnePiece|:1:-1] {
        print $ContourgShiftedOnePiece[i]
    }
set print

plot $Contourg u 1:2 skip 5 index 0 w l lw 2 lc 0 title columnheader(5)
set style fill transparent pattern 5 noborder
replot $ClosedCurveHatchArea u 1:2 w filledcurves lc 0
### end of code

Result:

Addition 2:

Actually, I like @Ethan's approach of creating an extra level contour line. This works well as long as the gradient is not too large. Otherwise you might get noticeable deformations of the second contour line (see red curve below). However, in the above examples with g1 and g2 you won't notice a difference. Another advantages is that the hatch lines are perpendicular to the curve. A disadvantage is that you might get some interruptions of the regular pattern.

The solution with a small shift of the original curve in x and/or y and filling areas doesn't work with oscillating or closed lines.

Below, the black hatched curves are a mix of these approaches.

Procedure:

  1. create a single contour line
  2. create an extended (ext) or shifted (shf) contourline (either by a new contour value or by shifting an existing one)
  3. order the contour line (ord)
  4. reverse the contour lin (rev)
  5. add the ordered (ord) and the extended,ordered,reversed (extordrev)
  6. plot the added contour line (add) with filledcuves

NB: if you want to shift a contour line by x,y you have to order first and then shift it, otherwise the macro @ContourOrder cannot order it anymore.

You see, it can get complicated. In summary, so far there are three approaches:

(a) extra level contour line and thick dashed line (@Ethan)

pro: short, works for oscillating and closed curves; con: bad if large gradient

(b) x,y shifted contour line and hatched filledcurves (@theozh)

pro: few parameters, clear picture; con: lengthy, only 4 hatch patterns)

(c) derivative of data point (@Dan Sp.)

pro: possibly flexibility for tilted hatch patterns; con: need of derivative (numerical if no function but datapoints), pattern depends on scale

The black curves are actually a mix of (a) and (b). The blue curve is (b). Neither (a) nor (b) will work nicely on the red curve. Maybe (c)? You could think of further mixing the approaches... but this probably gets also lengthy.

Code:

### contour lines with hashed side
set term wxt butt
reset session

f(x,y)=(x**2+y-11)**2+(x+y**2-7)**2
g1(x,y)=(x-5)**2+y**2
g2(x,y) = 4*x+y
g3(x,y) = -0.8-1/x**3+y

set xrange [0:6]
set yrange [0:6]
set isosample 250, 250
set key outside

set contour base
unset surface

set cntrparam levels disc 10,30,75,150,300,500,850,1500 
set table $Contourf
    splot f(x,y)
unset table

set cntrparam levels disc 26
set table $Contourg1
    splot g1(x,y)
unset table

set cntrparam levels disc 20
set table $Contourg2
    splot g2(x,y)
unset table

set cntrparam levels disc 0
set table $Contourg3
    splot g3(x,y)
unset table


# create some extra offset contour lines
# macro for setting contour lines
ContourCreate = '\
    set cntrparam levels disc Level; \
    set table @Output; \
        splot @Input; \
    unset table'

Level = 27.5
Input = 'g1(x,y)'
Output = '$Contourg1_ext'
@ContourCreate

Level = 20.5
Input = 'g2(x,y)'
Output = '$Contourg2_ext'
@ContourCreate

Level = 10
Input = 'f(x,y)'
Output = '$Contourf0'
@ContourCreate

Level = 13
Input = 'f(x,y)'
Output = '$Contourf0_ext'
@ContourCreate


# Macro for ordering the datapoints of the contour lines which might be split
ContourOrder = '\
stats @DataIn skip 6 nooutput; \
N = STATS_blank-1; \
set table @DataOut; \
    do for [i=N:0:-1] { plot @DataIn u 1:2 skip 5 index 0 every :::i::i with table }; \
unset table'

DataIn = '$Contourg1'
DataOut = '$Contourg1_ord'
@ContourOrder

DataIn = '$Contourg1_ext'
DataOut = '$Contourg1_extord'
@ContourOrder

DataIn = '$Contourg2'
DataOut = '$Contourg2_ord'
@ContourOrder

DataIn = '$Contourg2_ext'
DataOut = '$Contourg2_extord'
@ContourOrder

DataIn = '$Contourg3'
DataOut = '$Contourg3_ord'
@ContourOrder

set table $Contourg3_ordshf
    plot $Contourg3_ord u ($1+0.15):($2+0.15) w table   # shift the curve
unset table

DataIn = '$Contourf0'
DataOut = '$Contourf0_ord'
@ContourOrder

DataIn = '$Contourf0_ext'
DataOut = '$Contourf0_extord'
@ContourOrder

# Macro for reversing a datablock
ContourReverse = '\
set print @DataOut; \
    do for [i=|@DataIn|:1:-1] { print @DataIn[i]}; \
set print'

DataIn = '$Contourg1_extord'
DataOut = '$Contourg1_extordrev'
@ContourReverse

DataIn = '$Contourg2_extord'
DataOut = '$Contourg2_extordrev'
@ContourReverse

DataIn = '$Contourg3_ordshf'
DataOut = '$Contourg3_ordshfrev'
@ContourReverse

DataIn = '$Contourf0_extord'
DataOut = '$Contourf0_extordrev'
@ContourReverse

# Macro for adding datablocks
ContourAdd = '\
set print @DataOut; \
    do for [i=|@DataIn1|:1:-1] { print @DataIn1[i]}; \
    do for [i=|@DataIn2|:1:-1] { print @DataIn2[i]}; \
set print'

DataIn1 = '$Contourg1_ord'
DataIn2 = '$Contourg1_extordrev'
DataOut = '$Contourg1_add'
@ContourAdd

DataIn1 = '$Contourg2_ord'
DataIn2 = '$Contourg2_extordrev'
DataOut = '$Contourg2_add'
@ContourAdd

DataIn1 = '$Contourg3_ord'
DataIn2 = '$Contourg3_ordshfrev'
DataOut = '$Contourg3_add'
@ContourAdd

DataIn1 = '$Contourf0_ord'
DataIn2 = '$Contourf0_extordrev'
DataOut = '$Contourf0_add'
@ContourAdd

set style fill noborder 
set datafile commentschar " "
plot \
    for [i=1:8] $Contourf u 1:2:(i) skip 5 index i-1 w l lw 1.5 lc var title columnheader(5), \
    $Contourg1 u 1:2 skip 5 index 0 w l lw 3 lc 0 title columnheader(5), \
    $Contourg2 u 1:2 skip 5 index 0 w l lw 3 lc 0 title columnheader(5), \
    $Contourg3 u 1:2 skip 5 index 0 w l lw 3 lc 0 title columnheader(5), \
    $Contourg1_add u 1:2 w filledcurves fs transparent pattern 4 lc rgb "black" notitle, \
    $Contourg2_add u 1:2 w filledcurves fs transparent pattern 5 lc rgb "black" notitle, \
    $Contourg3_add u 1:2 w filledcurves fs transparent pattern 5 lc rgb "blue" notitle, \
    $Contourf0_add u 1:2 w filledcurves fs transparent pattern 6 lc rgb "red" notitle, \
### end of code

Result:

Addition 3:

If you plot a line with filledcurves, I guess gnuplot will connect the first and last point with a straight line and fills the enclosed area. In your circle/ellipse example the outer curve is cut at the top border of the graph. I guess that's why the script does not work in this case. You have to identify these points where the outer curve starts and ends and arrange your connected curve such that these points will be the start and end point. You see it's getting complicated...

The following should illustrate how it should work: make one curve where you start e.g. with the inner curve from point 1 to 100, then add point 1 of inner curve again, continue with point 1 of outer curve (which has opposite direction) to point 100 and add point 1 of outer curve again. Then gnuplot will close the curve by connecting point 1 of outer curve with point 1 of inner curve. Then plot it as filled with hatch pattern.

By the way, if you change your function g1(x,y) to g1(x,y)= x*y/2+(x+2)**2+(y-1.5)**2/2-2 (note the difference y-1.5 instead of y-2) everything works fine. See below.

Code:

### Hatching on a closed line
reset session

f(x,y)=x*exp(-x**2-y**2)+(x**2+y**2)/20
g1(x,y)= x*y/2+(x+2)**2+(y-1.5)**2/2-2

set xrange [-7:7]
set yrange [-7:7]
set isosample 250, 250
set key outside

set contour base
unset surface

set cntrparam levels disc 4,3.5,3,2.5,2,1.5,1,0.5,0 
set table $Contourf
    splot f(x,y)
unset table

set cntrparam levels disc 0
set table $Contourg1
    splot g1(x,y)
unset table

# create some extra offset contour lines
# macro for setting contour lines
ContourCreate = '\
    set cntrparam levels disc Level; \
    set table @Output; \
        splot @Input; \
    unset table'

Level = 1
Input = 'g1(x,y)'
Output = '$Contourg1_ext'
@ContourCreate

# Macro for ordering the datapoints of the contour lines which might be split
ContourOrder = '\
    stats @DataIn skip 6 nooutput; \
    N = STATS_blank-1; \
    set table @DataOut; \
        do for [i=N:0:-1] { plot @DataIn u 1:2 skip 5 index 0 every :::i::i with table }; \
    unset table'

DataIn = '$Contourg1'
DataOut = '$Contourg1_ord'
@ContourOrder

DataIn = '$Contourg1_ext'
DataOut = '$Contourg1_extord'
@ContourOrder

# Macro for reversing a datablock
ContourReverse = '\
set print @DataOut; \
    do for [i=|@DataIn|:1:-1] { print @DataIn[i]}; \
set print'

DataIn = '$Contourg1_extord'
DataOut = '$Contourg1_extordrev'
@ContourReverse

# Macro for adding datablocks
ContourAdd = '\
set print @DataOut; \
    do for [i=|@DataIn1|:1:-1] { print @DataIn1[i]}; \
    do for [i=|@DataIn2|:1:-1] { print @DataIn2[i]}; \
set print'

DataIn2 = '$Contourg1_ord'
DataIn1 = '$Contourg1_extordrev'
DataOut = '$Contourg1_add'
@ContourAdd

set style fill noborder 
set datafile commentschar " "
plot \
    for [i=1:8] $Contourf u 1:2:(i) skip 5 index i-1 w l lw 1.5 lc var title columnheader(5), \
    $Contourg1 u 1:2 skip 5 index 0 w l lw 2 lc 0 title columnheader(5), \
    $Contourg1_add u 1:2 w filledcurves fs transparent pattern 5 lc rgb "black" notitle
### end of code

Result:

这篇关于gnuplot等高线图阴影线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆