Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type error when rendering into SVG #667

Closed
mlarjim opened this issue Feb 1, 2023 · 2 comments
Closed

Type error when rendering into SVG #667

mlarjim opened this issue Feb 1, 2023 · 2 comments

Comments

@mlarjim
Copy link

mlarjim commented Feb 1, 2023

Hi,
I am getting the following error when using treeview:

File "/ete3/coretype/tree.py", line 1392, in render
    return drawer.render_tree(self, file_name, w=w, h=h,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/ete3/treeview/drawer.py", line 113, in render_tree
    x_scale, y_scale = save(scene, imgName, w=w, h=h, units=units, dpi=dpi)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/ete3/treeview/main.py", line 685, in save
    svg.setSize(QSize(w, h))
                ^^^^^^^^^^^
TypeError: arguments did not match any overloaded call:
  QSize(): too many arguments
  QSize(int, int): argument 1 has unexpected type 'float'
  QSize(QSize): argument 1 has unexpected type 'float'

Could you please fix this? Thank you!!

@Changwanseo
Copy link

That happens because qt dependency works different from when ete3 has built
The standard tactic is to revert pyqt5 version to previous, but I had hard time solving multiple it.

The heuristic, is to add underlying code in front of your code.
It will change how ete3 render works.

# ete3 patch
from __future__ import absolute_import
from __future__ import print_function
import ete3

# Patch for ete3 3.1.2 colliding with higher version PyQt5
def save(scene, imgName, w=None, h=None, dpi=90, take_region=False, units="px"):

    import colorsys
    import random
    import re
    import types
    from sys import stderr

    from PyQt5 import QtGui, QtCore
    from PyQt5.QtCore import (
        Qt,
        QPointF,
        QRect,
        QRectF,
        QBuffer,
        QByteArray,
        QThread,
        QIODevice,
        QMetaObject,
        QModelIndex,
        QObject,
        QRegExp,
        QSize,
        QSizeF,
        QVariant,
    )  # QString
    from PyQt5.QtSvg import QGraphicsSvgItem, QSvgGenerator
    from PyQt5.QtOpenGL import QGLFormat, QGLWidget
    from PyQt5.QtPrintSupport import QPrinter
    from PyQt5.QtWidgets import (
        QAction,
        QApplication,
        QCheckBox,
        QWidget,
        QColorDialog,
        QComboBox,
        QDialog,
        QDialogButtonBox,
        QFileDialog,
        QGraphicsEllipseItem,
        QGraphicsItem,
        QGraphicsItemGroup,
        QGraphicsLineItem,
        QGraphicsPathItem,
        QGraphicsPixmapItem,
        QGraphicsPolygonItem,
        QGraphicsRectItem,
        QGraphicsScene,
        QGraphicsSimpleTextItem,
        QGraphicsTextItem,
        QGraphicsView,
        QInputDialog,
        QItemDelegate,
        QLabel,
        QLineEdit,
        QListWidget,
        QMainWindow,
        QMenu,
        QMenuBar,
        QMessageBox,
        QPushButton,
        QSplitter,
        QStatusBar,
        QTableView,
        QTextEdit,
        QToolBar,
        QVBoxLayout,
        QWidget,
    )

    from PyQt5.QtGui import (
        QBrush,
        QColor,
        QCursor,
        QFont,
        QFontMetrics,
        QIcon,
        QImage,
        QPainter,
        QPainterPath,
        QPen,
        QPixmap,
        QPolygonF,
        QRadialGradient,
        QRegExpValidator,
        QStandardItemModel,
        QTransform,
    )

    QtCore.pyqtSignature = QtCore.pyqtSlot

    from ete3.treeview.svg_colors import SVG_COLORS, COLOR_SCHEMES

    import time

    ipython_inline = False
    if imgName == "%%inline":
        ipython_inline = True
        ext = "PNG"
    elif imgName == "%%inlineSVG":
        ipython_inline = True
        ext = "SVG"
    elif imgName.startswith("%%return"):
        try:
            ext = imgName.split(".")[1].upper()
        except IndexError:
            ext = "SVG"
        imgName = "%%return"
    else:
        ext = imgName.split(".")[-1].upper()

    main_rect = scene.sceneRect()
    aspect_ratio = main_rect.height() / main_rect.width()

    # auto adjust size
    if not w and not h:
        units = "px"
        w = main_rect.width()
        h = main_rect.height()
        ratio_mode = Qt.KeepAspectRatio
    elif w and h:
        ratio_mode = Qt.IgnoreAspectRatio
    elif h is None:
        h = w * aspect_ratio
        ratio_mode = Qt.KeepAspectRatio
    elif w is None:
        w = h / aspect_ratio
        ratio_mode = Qt.KeepAspectRatio

    # Adjust to resolution
    if units == "mm":
        if w:
            w = w * 0.0393700787 * dpi
        if h:
            h = h * 0.0393700787 * dpi
    elif units == "in":
        if w:
            w = w * dpi
        if h:
            h = h * dpi
    elif units == "px":
        pass
    else:
        raise Exception("wrong unit format")

    x_scale, y_scale = w / main_rect.width(), h / main_rect.height()

    if ext == "SVG":
        svg = QSvgGenerator()
        targetRect = QRectF(0, 0, w, h)
        svg.setSize(QSize(int(w), int(h)))
        svg.setViewBox(targetRect)
        svg.setTitle("Generated with ETE http://etetoolkit.org")
        svg.setDescription("Generated with ETE http://etetoolkit.org")

        if imgName == "%%return":
            ba = QByteArray()
            buf = QBuffer(ba)
            buf.open(QIODevice.WriteOnly)
            svg.setOutputDevice(buf)
        else:
            svg.setFileName(imgName)

        pp = QPainter()
        pp.begin(svg)
        scene.render(pp, targetRect, scene.sceneRect(), ratio_mode)
        pp.end()
        if imgName == "%%return":
            compatible_code = str(ba)
            print("from memory")
        else:
            compatible_code = open(imgName).read()
        # Fix a very annoying problem with Radial gradients in
        # inkscape and browsers...
        compatible_code = compatible_code.replace("xml:id=", "id=")
        compatible_code = re.sub(
            'font-size="(\d+)"', 'font-size="\\1pt"', compatible_code
        )
        compatible_code = compatible_code.replace("\n", " ")
        compatible_code = re.sub("<g [^>]+>\s*</g>", "", compatible_code)
        # End of fix
        if ipython_inline:
            from IPython.core.display import SVG

            return SVG(compatible_code)

        elif imgName == "%%return":
            return x_scale, y_scale, compatible_code
        else:
            open(imgName, "w").write(compatible_code)

    elif ext == "PDF" or ext == "PS":
        if ext == "PS":
            format = QPrinter.PostScriptFormat
        else:
            format = QPrinter.PdfFormat

        printer = QPrinter(QPrinter.HighResolution)
        printer.setResolution(dpi)
        printer.setOutputFormat(format)
        printer.setPageSize(QPrinter.A4)
        printer.setPaperSize(QSizeF(w, h), QPrinter.DevicePixel)
        printer.setPageMargins(0, 0, 0, 0, QPrinter.DevicePixel)

        # pageTopLeft = printer.pageRect().topLeft()
        # paperTopLeft = printer.paperRect().topLeft()
        # For PS -> problems with margins
        # print paperTopLeft.x(), paperTopLeft.y()
        # print pageTopLeft.x(), pageTopLeft.y()
        # print  printer.paperRect().height(),  printer.pageRect().height()
        # topleft =  pageTopLeft - paperTopLeft

        printer.setFullPage(True)
        printer.setOutputFileName(imgName)
        pp = QPainter(printer)
        targetRect = QRectF(0, 0, w, h)
        scene.render(pp, targetRect, scene.sceneRect(), ratio_mode)
    else:
        targetRect = QRectF(0, 0, w, h)
        ii = QImage(w, h, QImage.Format_ARGB32)
        ii.fill(QColor(Qt.white).rgb())
        ii.setDotsPerMeterX(dpi / 0.0254)  # Convert inches to meters
        ii.setDotsPerMeterY(dpi / 0.0254)
        pp = QPainter(ii)
        pp.setRenderHint(QPainter.Antialiasing)
        pp.setRenderHint(QPainter.TextAntialiasing)
        pp.setRenderHint(QPainter.SmoothPixmapTransform)

        scene.render(pp, targetRect, scene.sceneRect(), ratio_mode)
        pp.end()
        if ipython_inline:
            ba = QByteArray()
            buf = QBuffer(ba)
            buf.open(QIODevice.WriteOnly)
            ii.save(buf, "PNG")
            from IPython.core.display import Image

            return Image(ba.data())
        elif imgName == "%%return":
            ba = QByteArray()
            buf = QBuffer(ba)
            buf.open(QIODevice.WriteOnly)
            ii.save(buf, "PNG")
            return x_scale, y_scale, ba.toBase64()
        else:
            ii.save(imgName)

    return w / main_rect.width(), h / main_rect.height()


def patch():
    ete3.treeview.main.save = save
 
patch()

@mlarjim
Copy link
Author

mlarjim commented Feb 2, 2023

Thank you so much! I tried changing the following line in the file /ete3/treeview/main.py, as you did, and it worked for me:

        ...
        svg.setSize(QSize(w, h))
        ...
        ...
        svg.setSize(QSize(int(w), int(h)))
        ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants