如何组织图中的图例、颜色条和图像的位置?
How to organize the position of the legend, colorbar and image in the plot?
我正在尝试绘制一些数据,但我不喜欢这些项目的组织方式。
例如,我想要一个更大的图像和一个更小的颜色条。当我修改图形的大小时仍然不成比例。而且我还想将每个钻孔标记为图例,以便我可以识别它。
这是我现在的图像:
这是代码:
# Create data
l = [2, 3, 4, 5,6]
n = 20
labels = [item for item in l for i in range(n)]
random.shuffle(labels,random.random)
labels =np.array(labels)
label_unique = np.unique(labels)
n = 100
x = np.linspace(613000, 615000, num=n) + np.random.uniform(-5, 5, size=n)
y = np.linspace(7763800, 7765800, num=n) + np.random.uniform(-5, 5, size=n)
z = np.linspace(1230, 1260, num=n) + np.random.uniform(-5, 5, size=n)
cpt1 = pd.DataFrame(list(zip(x, y, z,labels)),
columns=['x','y', 'z','labels'])
l = [2, 3, 4, 5,6]
n = 60
labels = [item for item in l for i in range(n)]
random.shuffle(labels,random.random)
labels =np.array(labels)
label_unique = np.unique(labels)
cpt2 = pd.DataFrame(list(zip(x, y, z,labels)),
columns=['x','y', 'z','labels'])
n = 400
x = np.linspace(613000, 615000, num=n) + np.random.uniform(-7, 7, size=n)
y = np.linspace(7763800, 7765800, num=n) + np.random.uniform(-7, 7, size=n)
z = np.linspace(1230, 1260, num=n) + np.random.uniform(-7, 7, size=n)
l = [2, 3, 4, 5,6]
n = 80
labels = [item for item in l for i in range(n)]
random.shuffle(labels,random.random)
labels =np.array(labels)
label_unique = np.unique(labels)
cpt3 = pd.DataFrame(list(zip(x, y, z,labels)),
columns=['x','y', 'z','labels'])
cpt = [cpt1,cpt2,cpt3]
legend = cpt1.columns.values.tolist()
fig = plt.figure(figsize = (20, 9))
ax = plt.axes(projection ="3d")
# Add x, y gridlines
ax.grid(b = True, color ='grey',
linestyle ='-.', linewidth = 0.3,
alpha = 0.2)
# Creating color map
my_cmap = plt.get_cmap('hsv')
for count, c in enumerate(cpt):
x = c.x
y = c.y
z = c.z
colorz = c.labels
# Creating plot
sctt = ax.scatter3D(x, y, z,
alpha = 0.8,
c = colorz,
cmap = my_cmap,
marker ='^',label = legend[count])
ax.set_xlabel('X-axis', fontweight ='bold')
ax.set_ylabel('Y-axis', fontweight ='bold')
ax.set_zlabel('Z-axis', fontweight ='bold')
fig.colorbar(sctt, ax = ax, shrink = 0.3, aspect = 5,orientation="horizontal")
plt.legend(bbox_to_anchor=(1.5,1), loc="upper left")
plt.show()
问题分为两部分,此答案至少分为三部分。
设置导入和合成数据。每当我发现自己重新输入或 copy/pasting 具有不同参数的复杂行时,我都会改用一个函数:
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
# Fake data of about the right shape
def syncoords(pars, n):
'''pars: tuple or list of min, max, abs_variance'''
return np.linspace(pars[0], pars[1], num=n) + \
np.random.uniform(-1*pars[2], pars[2], size=n)
def synbore(n, xparams, yparams, zparams, zonevalues):
'''create n entries for x,y,z, and zone from parameter tuples
xyzparams: tuple of min, max, abs_variance
zonevalues: list of zone values'''
return pd.DataFrame({'x': syncoords(xparams, n),
'y': syncoords(yparams, n),
'z': syncoords(zparams, n),
'Zone': np.random.choice(zonevalues, size=n)})
boreparams = [['melaza', 10,
(61300, 61500, 5), (77638, 77658, 5), (5023, 5400, .5),
[2,3,4,5,6]],
['miel', 23,
(45000, 45555, 5), (69712, 68800, 5), (4701, 5100, .7),
[2,3,4,5,6]],
['jalea', 50,
(50432, 50000, 6), (38200, 38600, 6), (5050, 5600, .9),
[4,5,6,7,8]]]
我没有停留在数据帧列表中,因为我总是希望我的数据与其 ID 字符串“一起旅行”。当我有两个列表时,我必须验证编辑和更新是否始终匹配。把它变成一个字典并没有让剩下的代码不再存在,所以我们的数据集的字典:
# I like my data to travel with its ID, which dictionaries are great for.
# boredict entries: {"ID": xyzZone_dataframe}
# easy to make a dict from a list of (k, v) pairs,
# so a lambda function to do that:
boredict = dict(map(lambda l:(l[0],
synbore(l[1],l[2],l[3],l[4],l[5])),
boreparams))
# Get ready to plot
fig = plt.figure(figsize=(11, 8.5)) # Or A? papersize
ax = plt.axes(projection ="3d")
ax.set_xlabel('X-axis', fontweight ='bold')
ax.set_ylabel('Y-axis', fontweight ='bold')
ax.set_zlabel('Z-axis', fontweight ='bold')
ax.grid(b = True, color ='grey',
linestyle ='-.', linewidth = 0.3,
alpha = 0.2)
# TODO: collect the max-min of all the Zones so one colormap works for all
# see https://matplotlib.org/stable/tutorials/colors/colormapnorms.html
# and https://matplotlib.org/stable/tutorials/colors/colorbar_only.html
for bname in boredict:
# plot the actual bore data in 3D+colormap
bdata = boredict[bname]
sctt = ax.scatter3D(bdata.x, bdata.y, bdata.z,
alpha = 0.8,
c = bdata.Zone,
cmap = plt.get_cmap('hsv'),
marker ='^')
# and a different marker to match the bore with the legend
ax.scatter3D(bdata.x[-1:], bdata.y[-1:], bdata.z[-1:] + 25,
marker = 'v',
s = 80,
label = bname)
最后是剧情布局管理。 3D 绘图需要大量的空白来让角旋转,但是您可以 trim 填充颜色条 (pad = 0
) 和图形本身,使用 subplots_adjust
。我也喜欢更大但更细的颜色条。
fig.colorbar(sctt, ax = ax,
shrink = 0.4, aspect = 16, pad = 0,
orientation="horizontal")
plt.legend(bbox_to_anchor=(1.1, .8), loc="upper left")
fig.subplots_adjust(left=0, right=1,bottom=0,top=1) #reduce whitespace around the fig
plt.show()
这个图还需要做一件事——在这里,我们根据要在循环中绘制的最后一个数据帧创建一个颜色条,仅那个数据帧。但也许数据帧有不同的 Zone
数据范围!我们想要一个可以同时准确应用于所有数据的颜色条。这意味着要查看所有数据两次,一次是为了弄清楚颜色条的范围是什么,然后再次将它们与整体颜色条一起绘制出来。我在您要执行此操作的代码中添加了#TODO 注释,并附有指向现有 questions/answers/examples.
的链接
我正在尝试绘制一些数据,但我不喜欢这些项目的组织方式。 例如,我想要一个更大的图像和一个更小的颜色条。当我修改图形的大小时仍然不成比例。而且我还想将每个钻孔标记为图例,以便我可以识别它。
这是我现在的图像:
这是代码:
# Create data
l = [2, 3, 4, 5,6]
n = 20
labels = [item for item in l for i in range(n)]
random.shuffle(labels,random.random)
labels =np.array(labels)
label_unique = np.unique(labels)
n = 100
x = np.linspace(613000, 615000, num=n) + np.random.uniform(-5, 5, size=n)
y = np.linspace(7763800, 7765800, num=n) + np.random.uniform(-5, 5, size=n)
z = np.linspace(1230, 1260, num=n) + np.random.uniform(-5, 5, size=n)
cpt1 = pd.DataFrame(list(zip(x, y, z,labels)),
columns=['x','y', 'z','labels'])
l = [2, 3, 4, 5,6]
n = 60
labels = [item for item in l for i in range(n)]
random.shuffle(labels,random.random)
labels =np.array(labels)
label_unique = np.unique(labels)
cpt2 = pd.DataFrame(list(zip(x, y, z,labels)),
columns=['x','y', 'z','labels'])
n = 400
x = np.linspace(613000, 615000, num=n) + np.random.uniform(-7, 7, size=n)
y = np.linspace(7763800, 7765800, num=n) + np.random.uniform(-7, 7, size=n)
z = np.linspace(1230, 1260, num=n) + np.random.uniform(-7, 7, size=n)
l = [2, 3, 4, 5,6]
n = 80
labels = [item for item in l for i in range(n)]
random.shuffle(labels,random.random)
labels =np.array(labels)
label_unique = np.unique(labels)
cpt3 = pd.DataFrame(list(zip(x, y, z,labels)),
columns=['x','y', 'z','labels'])
cpt = [cpt1,cpt2,cpt3]
legend = cpt1.columns.values.tolist()
fig = plt.figure(figsize = (20, 9))
ax = plt.axes(projection ="3d")
# Add x, y gridlines
ax.grid(b = True, color ='grey',
linestyle ='-.', linewidth = 0.3,
alpha = 0.2)
# Creating color map
my_cmap = plt.get_cmap('hsv')
for count, c in enumerate(cpt):
x = c.x
y = c.y
z = c.z
colorz = c.labels
# Creating plot
sctt = ax.scatter3D(x, y, z,
alpha = 0.8,
c = colorz,
cmap = my_cmap,
marker ='^',label = legend[count])
ax.set_xlabel('X-axis', fontweight ='bold')
ax.set_ylabel('Y-axis', fontweight ='bold')
ax.set_zlabel('Z-axis', fontweight ='bold')
fig.colorbar(sctt, ax = ax, shrink = 0.3, aspect = 5,orientation="horizontal")
plt.legend(bbox_to_anchor=(1.5,1), loc="upper left")
plt.show()
问题分为两部分,此答案至少分为三部分。
设置导入和合成数据。每当我发现自己重新输入或 copy/pasting 具有不同参数的复杂行时,我都会改用一个函数:
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
# Fake data of about the right shape
def syncoords(pars, n):
'''pars: tuple or list of min, max, abs_variance'''
return np.linspace(pars[0], pars[1], num=n) + \
np.random.uniform(-1*pars[2], pars[2], size=n)
def synbore(n, xparams, yparams, zparams, zonevalues):
'''create n entries for x,y,z, and zone from parameter tuples
xyzparams: tuple of min, max, abs_variance
zonevalues: list of zone values'''
return pd.DataFrame({'x': syncoords(xparams, n),
'y': syncoords(yparams, n),
'z': syncoords(zparams, n),
'Zone': np.random.choice(zonevalues, size=n)})
boreparams = [['melaza', 10,
(61300, 61500, 5), (77638, 77658, 5), (5023, 5400, .5),
[2,3,4,5,6]],
['miel', 23,
(45000, 45555, 5), (69712, 68800, 5), (4701, 5100, .7),
[2,3,4,5,6]],
['jalea', 50,
(50432, 50000, 6), (38200, 38600, 6), (5050, 5600, .9),
[4,5,6,7,8]]]
我没有停留在数据帧列表中,因为我总是希望我的数据与其 ID 字符串“一起旅行”。当我有两个列表时,我必须验证编辑和更新是否始终匹配。把它变成一个字典并没有让剩下的代码不再存在,所以我们的数据集的字典:
# I like my data to travel with its ID, which dictionaries are great for.
# boredict entries: {"ID": xyzZone_dataframe}
# easy to make a dict from a list of (k, v) pairs,
# so a lambda function to do that:
boredict = dict(map(lambda l:(l[0],
synbore(l[1],l[2],l[3],l[4],l[5])),
boreparams))
# Get ready to plot
fig = plt.figure(figsize=(11, 8.5)) # Or A? papersize
ax = plt.axes(projection ="3d")
ax.set_xlabel('X-axis', fontweight ='bold')
ax.set_ylabel('Y-axis', fontweight ='bold')
ax.set_zlabel('Z-axis', fontweight ='bold')
ax.grid(b = True, color ='grey',
linestyle ='-.', linewidth = 0.3,
alpha = 0.2)
# TODO: collect the max-min of all the Zones so one colormap works for all
# see https://matplotlib.org/stable/tutorials/colors/colormapnorms.html
# and https://matplotlib.org/stable/tutorials/colors/colorbar_only.html
for bname in boredict:
# plot the actual bore data in 3D+colormap
bdata = boredict[bname]
sctt = ax.scatter3D(bdata.x, bdata.y, bdata.z,
alpha = 0.8,
c = bdata.Zone,
cmap = plt.get_cmap('hsv'),
marker ='^')
# and a different marker to match the bore with the legend
ax.scatter3D(bdata.x[-1:], bdata.y[-1:], bdata.z[-1:] + 25,
marker = 'v',
s = 80,
label = bname)
最后是剧情布局管理。 3D 绘图需要大量的空白来让角旋转,但是您可以 trim 填充颜色条 (pad = 0
) 和图形本身,使用 subplots_adjust
。我也喜欢更大但更细的颜色条。
fig.colorbar(sctt, ax = ax,
shrink = 0.4, aspect = 16, pad = 0,
orientation="horizontal")
plt.legend(bbox_to_anchor=(1.1, .8), loc="upper left")
fig.subplots_adjust(left=0, right=1,bottom=0,top=1) #reduce whitespace around the fig
plt.show()
这个图还需要做一件事——在这里,我们根据要在循环中绘制的最后一个数据帧创建一个颜色条,仅那个数据帧。但也许数据帧有不同的 Zone
数据范围!我们想要一个可以同时准确应用于所有数据的颜色条。这意味着要查看所有数据两次,一次是为了弄清楚颜色条的范围是什么,然后再次将它们与整体颜色条一起绘制出来。我在您要执行此操作的代码中添加了#TODO 注释,并附有指向现有 questions/answers/examples.