如何在兩條曲線之間上色?
做一個論文插圖
有兩條曲線,曲線是由離散點給出的。
希望能夠給兩條曲線所夾著的部分上色或者畫上陰影。
——————————————————————————這組曲線有以下特徵:
1、離散點構成
2、Y相同,X不同最後用matlab搞定了,把兩條曲線連起來形成一個閉合的圈,然後用fill填色
按照這個思路,用origin也可以搞定,最終效果是這樣的
我把數據也貼出來,格式為XXY0.00
0.00
0
0.12
0.04
2
0.24
0.08
4
0.36
0.11
6
0.47
0.15
8
0.59
0.19
10
0.71
0.23
12
0.83
0.26
14
0.95
0.30
16
1.07
0.34
18
1.21
0.38
20
1.38
0.41
22
1.78
0.45
24
2.84
0.49
26
3.45
0.52
28
3.88
0.56
30
4.33
0.60
32
4.79
0.64
34
5.25
0.64
36
5.89
0.30
38
6.16
0.68
40
6.51
0.84
42
6.89
0.98
44
7.27
1.14
46
7.67
1.39
48
8.07
1.95
50
8.47
5.30
52
8.89
5.82
54
9.30
6.14
56
9.71
6.48
58
10.11
6.90
60
10.52
7.56
62
10.92
8.18
64
11.32
8.55
66
11.72
8.86
68
12.13
9.16
70
12.53
9.46
72
12.93
9.77
74
13.33
10.07
76
13.73
10.38
78————————————————————————————————
Mathematica中用Filling命令就行了
x = Range[0, 2 Pi, 0.1];
y = {Sin[x], Sin[x] + 0.5};
ListPlot[y, Filling -&> {1 -&> {2}}, Joined -&> #] /@ {True, False};
% // Column
陰影填充,要改變細節可以調整MeshFunctions和MeshStyle,如MeshFunctions -&> {#2 }為水平陰影線
data = Table[{{x, Sin[x]}, {x, Cos[x]}}, {x, 0, 2 Pi, 0.1}];
plt = ListLinePlot[Transpose@data, Filling -&> {1 -&> {2}}];
poly = Cases[Normal@plt, Polygon[p_] :&> p, -1];
RegionPlot[Graphics`Mesh`InPolygonQ[#, {x, y}] /@ poly // Evaluate,
{x, 0, 2 [Pi]}, {y, -1.5, 1.5}, Mesh -&> 50, PlotPoints -&> 50,
MeshFunctions -&> {# - #2 }, MeshShading -&> {None},
BoundaryStyle -&> Black] // Quiet
這種效果嗎?
d1 = Import["D:/data.txt", "Table"];
d2 = d1[[;; , #]] /@ {{1, 3}, {2, 3}};
ListLinePlot[d2, Filling -&> {1 -&> {2}}, Frame -&> 1]
ListLinePlot[d2, Frame -&> 1, Filling -&> {1 -&> Top, 2 -&> {Top, White}}]
如果用R的話,ggplot2裡面的geom_ribbon完全可以滿足你的要求。如下是自己剛剛做好的一張圖:
源代碼只有三行:
pt &<- ggplot(plotting, aes(x=time))
pt &<- pt + geom_ribbon(aes(ymin=x25, ymax=x975), colour="mistyrose", fill="mistyrose")+geom_ribbon(aes(ymin=x05, ymax=x95), colour="mistyrose2", fill="mistyrose2")+geom_line(aes(x=time, y=medn), colour="red", size=0.7)
pt &<- pt+scale_y_log10()橫向陰影:
縱向陰影:
縱向陰影:十字陰影(其實就是前面兩個疊加啦,呵呵):
十字陰影(其實就是前面兩個疊加啦,呵呵):
matlab代碼:
data 取自您貼出的數據(但略微改動,我在後面附出改動的地方)
x1 = data(:,1);
x2 = data(:,2);
y = data(:,3);
%%%%%%%%%%%%%%%% 橫向陰影 %%%%%%%%%%%%%%%%
%%% 為畫陰影線對原離散數據進行的插值
y_int = 1.5;
y_interp = min(y):y_int:max(y);
x1_interp = interp1(y,x1,y_interp);
x2_interp = interp1(y,x2,y_interp);
%%% 畫出原來的線條
plot( x1, y, "black" )
hold on
plot( x2, y, "black" )
plot([13.73 10.38], [78,78], "black")
%%% 根據插值得到的數據逐條畫陰影線
L = length(y_interp);
for i = 1:L
line( [x1_interp(i), x2_interp(i)], [y_interp(i),y_interp(i)],"color","black" )
end
%%%%%%%%%%%%%%%% 縱向陰影 %%%%%%%%%%%%%%%%
%%% 插值,但縱向陰影相對麻煩,需要分段插值
x_int = 1;
x1_interp = min(x1):x_int:max(x1);
x2_interp = min(x2):x_int:max(x2);
L1 = length( x1_interp )
L2 = length( x2_interp )
y1_interp = interp1( x1, y, x1_interp );
y2_interp = interp1( x2, y, x2_interp ); %%% 插值問題
plot( x1, y, "black" )
hold on
plot( x2, y, "black" )
plot([13.73 10.38], [78,78], "black")
for i = 1:L2
line( [x1_interp(i), x1_interp(i)], [ y1_interp(i), y2_interp(i)],"color","black" )
end
line( [x1_interp(i), x1_interp(i)], [ y1_interp(i), 78],"color","black" )
end
%%%%%%%%%%%
然後對間隔調整,也就是間隔值 y_int x_int 的調整會得到不同密集程度的陰影圖,例如
x_int 取步不同值時
大概有這種簡單調節的效果。
大概有這種簡單調節的效果。
最後把上面的程序打包丟到一個function里可以實現簡單的這類圖形的作圖和簡單調整陰影間隔的調整的自動化工作。如果需要更複雜比如其他方向的陰影線可能要對線條旋轉之類的工作,如果需要圖案填充有個思路從像素角度去填充。
......
4.79 0.64 34
5.25 0.64 36
5.89 0.30 38
6.16 0.68 40
....,..
這裡的第三行5.89 0.30 0.38 中那個0.30我猜測是有數據有誤,按這個數據畫出來的圖形也和您貼出來的不太符合,所以我改成0.65;另外前面有兩個0.64,由於插值函數要求函數是嚴格增的,所以把它改成0.640001
MATLAB的代碼可以簡化一下:
x = (0:100)"/50*pi;
y = [sin(x) sin(x+2)];
subplot(2,1,1)
patch([x;flipud(x)],[y(:,1);flipud(y(:,2))],"r","FaceA",.2,"EdgeA",0)
line(x,y,"linewidth",2), axis([-.1 6.5 -1.1 1.1])
subplot(2,1,2)
X = x([1 end]); Y = [min(y(:));max(y(:))];
line(interp2([X";X"*[97,-3;3,103]/100],1:.02:2,[1;2]),Y*ones(1,51),"co",[.8 .8 .8])
patch([x;flip(x);xlim";flip(xlim")],[y(:,1);flip(y(:,2));Y([2 2 1 1])],"w","EdgeA",0)
line(x,y,"linewidth",2), axis([-.1 6.5 -1.1 1.1])
看了一下上面的答案,這裡補充一下Python的matplotlib模塊中「fill_between」不但可以實現曲線之間的色彩填充,還能夠直接指定在哪些地方進行填充。
樓上關於「fill_between( )」的運用是預先設定「boolean」下標來指定具體在哪些地方填充,實際上「fill_between( )」本身設定了「where」參數來實現該功能。
fill_between(x, y1, y2=0, where=None, interpolate=False, hold=None, **kwargs)
Make filled polygons between two curves.
Call signature::
fill_between(x, y1, y2=0, where=None, **kwargs)
下面簡單看下在sin(x)與cos(x)之間位於cos(x) &> sin(x)處的填充實例:
from matplotlib import pyplot as plt
import numpy as np
# 導入相應模塊
x = np.linspace(-4*np.pi, 4*np.pi, 1024)
y1 = np.sin(x)
y2 = np.cos(x)
# 簡單畫出兩條曲線
plt.plot(x, y1, "g-", linewidth=2.0, label="$sin(x)$")
plt.plot(x, y2, "b-", linewidth=2.0, label="$cos(x)$")
# 這裡不需要預先利用boolean下標來設定填充區域,而直接通過y2&>y1等價實現
plt.fill_between(x, y2, y1, y2 &> y1, color="#ff0000", alpha=0.3)
# 對圖表進行簡單修飾
plt.xlim(-4*np.pi, 4*np.pi)
plt.xticks(np.arange(-4*np.pi, 5*np.pi, np.pi),
["$%dpi$" % n for n in range(-4,5)])
plt.ylim(-2.0, 2.0)
plt.legend()
plt.grid(True)
plt.show()
如果用 Python 的話。用 fill_between 函數。
下邊是我寫的一個例子,有點長,不過其實重點只有 fill_between 一句而已,其他都是些為了讓例子跑起來的輔助語句。from matplotlib import collections as coll, pyplot as plt
import numpy as np
# 構建四個函數
def fun1(x):
return (2*x - x**2)**0.5
def fun2(x):
return 1 - (2*x - x**2)**0.5
def fun3(x):
return (1.0 + (1-4*x*x)**0.5)/2
def fun4(x):
return (1.0 - (1-4*x*x)**0.5)/2
# 生成離散的 x 坐標 從 0~1.01 精度 0.002
x = np.arange(0, 1.01, 0.002)
# 取得離散的函數值
y1 = fun1(x)
y2 = fun2(x)
y3 = fun3(x)
y4 = fun4(x)
# 畫出曲線
plt.plot(x, y1, alpha=0.8)
plt.plot(x, y2, alpha=0.8)
plt.plot(x, y3, alpha=0.8)
plt.plot(x, y4, alpha=0.8)
# 根據大致的函數圖象取出要填充部分的最大值和最小值。
y_up = np.minimum(y1, y3)
y_down = np.maximum(y2, y4)
# 取出要填充部分的 x 坐標(即就是所有 y_up &> y_down 處的 x 坐標,下同)
x = x[y_up&>y_down]
yu = y_up[y_up&>y_down]
yd = y_down[y_up&>y_down]
# 值得注意的是此處 x 和 yu, yd 都是長度一致的數組,每次取對應處的值
# 填充 x 處的從 yu 到 yd 的部分.
plt.fill_between(x, yu, yd, alpha=0.3)
# 顯示出來
plt.axis("scaled")
plt.show()
我覺得用Mma應該學會善用幫助文檔,裡面各種參數的例子都有。。不合適就再逛逛最下面的相關函數。。
為了顏色好看,可以用 alpha 進行調整~~哦,我說的是 MATLAB
-----外行亂入一下,覺得答偏了的話請摺疊-------
既然是論文插圖的畫,就不需要你在軟體里也是這樣樣子咯?
那為什麼不用photoshop填個色呢?
Paint Bucket Tool,油漆桶工具,點一下塗一片,顏色任選效果好。
妥妥的。畫圖-油漆桶
推薦閱讀: