簡體   English   中英

使用兩個具有沖突 Python 版本要求的庫?

[英]Using two libraries with conflicting Python version requirements?

我有兩個需要在同一環境中運行的 Python 庫。 它們是pptktorch-scatter並且沒有重疊的 Python 版本要求; pptk <= 3.7 和torch-scatter >= 3.8。 他們都在某種程度上大量使用 C++ 來增強其功能,我懷疑我是否具備為所需的 Python 版本更新/更新它們所需的技術技能。

鑒於pptk是一個繪圖庫,我看到的唯一解決方案是創建一個 Python 3.8 環境並安裝torch-scatter 然后編寫一個腳本來獲取我希望提供給pptk的任何數據以顯示,將其腌制到NamedTemporaryFile 最后啟動一個新進程並將文件名作為參數傳遞給它,該進程將運行安裝了pptk的 Python 3.7 環境,加載文件並顯示數據。

有沒有比描述的更簡單的解決方案? Python 中是否有一些支持來調用不同的 Python 版本庫並執行一些自動編組?

如果沒有其他人提供更好的解決方案,並且將來有人在這里絆倒,這就是我實施的 WYSIWYG 解決方案。

function pptk_subprocess接收我顯示的數據,執行一些操作,並將其寫入NamedTemporaryFile 然后將文件名傳遞到commands字符串中。 該字符串啟動了pptk庫所在的 Anaconda 環境,並在該環境中運行當前的__file__ __main__中加載此文件並讀取數據以顯示。 還可以選擇通過相同的NamedTemporaryFile將一些數據寫回pptk_subprocess “上下文”,由shutil.copyfile數據寫入其中。

該解決方案似乎只能從命令行工作,而不是通過 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:\ProgramData\Anaconda3\Scripts\\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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM