我有两个Python库,需要在同一环境中运行。它们是pptk
和torch-scatter
,没有重叠的Python版本要求;pptk
<=3.7和torch-scatter
>=3.8.他们都大量使用C++来增强功能,我怀疑我是否具备为所需的Python版本更新/降级所需的技术技能。
假设pptk
是一个绘图库,我看到的唯一解决方案是创建一个Python 3.8环境并安装torch-scatter
。然后编写一个脚本,将我希望提供给pptk
的任何数据显示出来,并将其pickle到NamedTemporaryFile
。最后启动一个新进程并将文件名作为参数传递给它,该进程将运行安装了pptk
的Python 3.7环境,加载文件并显示数据。
是否有比所描述的更简单的解决方案Python是否支持调用不同版本的Python库并执行一些自动编组?
如果没有其他人提供更好的解决方案,而将来有人在这里遇到了麻烦,下面是我实现的所见即所得的解决方案。
函数pptk_subprocess
接收我显示的数据,执行一些操作,并将其写入NamedTemporaryFile
。然后将文件名传递到commands
字符串中。此字符串启动pptk
库所在的Anaconda环境,并在该环境中运行当前__file__
。在__main__
中,加载该文件并读取数据以进行显示。还有将一些数据写回CCD_ 16〃的选项;上下文";通过相同的CCD_ 17由CCD_
这个解决方案似乎只能从命令行工作,而不能通过IDE的run
功能。
import os
import sys
import math
import time
import shutil
import tempfile
import subprocess
import numpy as np
import matplotlib.image as mpimg
from matplotlib.colors import ListedColormap
"""
Python 3.7 functions
"""
def subprocess_pptk_lidar_image(points, labels):
import pptk
"""
Plot a point cloud with pptk and return a TemporaryFile of a screenshot
Note: User MUST .CLOSE() the file.
"""
# Continually attempt to open pptk, plot, and capture an image. pptk sometimes selects a port in use.
tmpimg = None
got_image = False
num_tries = 0
while not got_image:
if num_tries > 10:
raise RuntimeError(f'Attempted to open pptk 10 times. Something is wrong.')
tmpimg = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
try:
v = pptk.viewer(points)
v.attributes(labels)
v.set(point_size=0.02)
v.set(r=500)
v.set(phi=math.radians(90))
v.set(theta=math.radians(65))
v.capture(tmpimg.name)
time.sleep(1.5)
got_image = True
except Exception as e:
num_tries += 1
continue
return tmpimg
def subprocess_interactive_lidar_pptk(points, labels):
import pptk
v = pptk.viewer(points[:, 0:3])
v.attributes(labels)
v.set(point_size=0.05)
v.wait() # Wait until the user hits enter.
"""
Python 3.8 functions
"""
def generate_colormap_from_labels_colors(labels: dict, colors: dict):
"""
Given a dictionary of labels {int: 'label'} and colors {int: 'color'} generate a ColorMap
"""
# If there is a label 'unclassified' label ensure its color is 'WhiteSmoke' and not 'Black'
if 'unclassified' in labels.values():
# Get the index of the unclassified label in the label_dict
unclass_index = list(labels.keys())[list(labels.values()).index('unclassified')]
colors[unclass_index] = 'WhiteSmoke'
color_map = ListedColormap(colors.values())
return color_map
def pptk_subprocess(points, labels=None, label_dict=None, color_dict=None, interactive=False):
# Generate "fake" labels by using the Z values for coloring
if labels is None:
labels = np.copy(points[:, 2])
labels = (labels - np.min(labels)) / np.ptp(labels)
# Generate the labels as RGB values if a colordict is given
if label_dict is not None and color_dict is not None:
colormap = generate_colormap_from_labels_colors(label_dict, color_dict)
labels = colormap(labels.astype(np.int32))
# Package the data into a temporary file to hand to the subprocess
datafile = tempfile.NamedTemporaryFile(suffix='.npz', delete=False)
np.savez(datafile.name, points=points, labels=labels, interactive=np.array([interactive]))
# Start a process that calls this file
commands = f'C:ProgramDataAnaconda3Scripts\activate.bat && conda activate torch-pptk-py37 && python {__file__} {datafile.name}'
subprocess.run(commands, shell=True)
# If we were not interactive the subprocess wrote and image back into the datafile
if not interactive:
plot_image = mpimg.imread(datafile.name)
datafile.close()
os.remove(datafile.name)
return plot_image
return None
if __name__ == '__main__':
# Dumbly figure out which argument is the datafile path
datafile_path = None
for a in sys.argv:
if os.path.isfile(a) and '.py' not in a:
datafile_path = a
# Load and parse the points and labels from the file
data = np.load(datafile_path)
points = data['points']
labels = data['labels']
interactive = data['interactive'][0]
if interactive:
# Display this plot and wait for it to close from user input
subprocess_interactive_lidar_pptk(points, labels)
else:
# Generate an image of the plot and get a NamedTempFile with it as an image
tmpimg = subprocess_pptk_lidar_image(points, labels)
# Copy the image from the returned file into the datafile
shutil.copyfile(tmpimg.name, datafile_path)
# Close and delete the temporary file
tmpimg.close()
os.remove(tmpimg.name)