Julia에서 브라우저로 출력

소개



Gadfly.jl의 코드를 보면 브라우저에서의 표시가 의외로 간단하다고 느꼈기 때문에 1부터 구현해 보겠습니다.



실질적인 처리는 간단하고,
  • 보려는 개체를 기반으로 임시 파일 temp.html 만들기
  • 명령 cmd /c start temp.html 실행
  • *.html과 연결된 브라우저에서 임시 파일이 열립니다

  • 뿐이다.

    문제가 되는 것은 출력처의 설정 방법으로, 이 기사에서 자세하게 설명해 가고 싶다.

    [구현한 코드]
    htps : // 기 st. 기주 b. 코 m/ㅃ리 my/2962c626941361f8b789훗3f669b5b15

    객체와 표현


    show의 작업은 대상 객체를 지정된 MIME 유형으로 io로 출력하는 것입니다. 이 기사의 맥락에서 show는 표시에 적합한 형식으로 객체를 표현한다는 해석이 솔직하다고 생각한다.
    struct Hoge end
    
    function Base.show(io::IO, ::MIME"text/html", ::Hoge)
        html = """
        <!DOCTYPE html>
        <html>
            <head>
                <title>Julia Output</title> 
            </head>
            <body>
                Hello, <strong>Julia</strong> !!!
            </body>
        </html>
        """
        write(io, html)
        flush(io)
    end
    
    x = Hoge()
    

    Julia/Jupyter에서 이미지 표시 구현
    htps : // 이 m / ㄹ리 my / ms / b5604b41247 8 7 00

    출력 대상 관리



    Julia 에서의 출력처는 AbstractDisplay 형의 오브젝트로 나타난다. 예를 들면, REPL의 출력부나 에디터의 플롯 페인, Jupyter 등에 대응하는 것과 같은 오브젝트가 존재한다.

    사용 가능한 디스플레이는 Base.Multimedia.displays라는 배열에 유지되고 표시시에는 뒤쪽이 우선된다. pushdisplay(d)는 배열의 끝에 디스플레이를 추가합니다.
    struct MyDisplay <: AbstractDisplay end
    
    pushdisplay(MyDisplay())
    

    자신의 디스플레이를 만들고 싶은 경우, display(d, args...) 로 다중 디스패치 할 수 있는 형태를 만들면 된다. 실제의 처리는 display에 써 가게 된다.

    display 메소드 구현



    디스플레이 트리거



    객체 x를 표시 할 때 display(x)를 시작점으로 생각합시다. 아마도 여러 장면에서 암묵적으로 불리고 있다고 생각된다.

    1 인수 display(x)는 적절한 디스플레이 d를 선택하고 2 인수 display(d, x)를 호출한다.

    여기서, 디스플레이에 의존하는 처리로 이행한다.

    MIME 선택


    function Base.display(d::MyDisplay, @nospecialize x)
        if showable(MIME("text/html"), x)
            display(d, MIME("text/html"), x)
        else
            throw(MethodError(Base.display, (d, x)))
        end
    end
    

    2 인수의 display(d, x) 역할은 적절한 MIME의 선택입니다. 여기서는 text/html에만 대응하고 있지만, 디스플레이가 복수의 MIME를 표시할 수 있으면, 미리 정한 우선도에 따라 MIME를 결정한다.
    x 를 표현할 수 있고 d 에 표시할 수 있는 MIME 가 발견되지 않으면 에러를 던지지만, 그 경우는 호출원 display(x) 가 다른 디스플레이를 시도한다.

    적절한 MIME을 선택할 수 있으면 3 인수 display(d, mime, x)를 호출합니다.

    출력



    3 인수 display(d, mime, x)가 호출되면 출력 준비가 완료되었습니다.

    여기서 f::IO를 임시 파일로 준비하고 show에 연결합니다.
    using DefaultApplication
    
    function Base.display(::MyDisplay, mime::MIME"text/html", @nospecialize x)
        filename = tempname() * ".html"
        open(filename, "w") do f
            show(f, mime, x)
        end
        # run(`cmd /c start $(filename)`) # Windows
        DefaultApplication.open(filename; wait=true)
        nothing
    end
    
    # x = Hoge()
    display(x)
    

    나머지는 내보낸 임시 파일을 열기만 하지만 OS 의존성을 피하기 위해 DefaultApplication.jl 패키지를 사용했다.

    htps : // 기주 b. 코 m / 기오 ゃ 네 네 ぃ 아 /가 dfly. jl/bぉb/까지 r/src/가 dfly. jl#L1047-L1071
    htps : // 기주 b. 이 m / t pp p /로 푹신한 l 탓 p ㅃ 카치온. jl/bぉb/마s r/src/로 보는 l타p pㅃ카치온. jl#L12-L24

    【보충】 Jupyter에서의 암시적인 표시



    Jupyter는 명시 적으로 display하지 않고 셀의 반환 값을 자동으로 표시합니다.

    이 기사의 코드로 거동을 확인하면, 자동 표시라면 디스플레이의 우선도가 무시되어 버리는 것을 알았다. 즉, display(x)가 아니라 display(IJulia.InlineDisplay(), x) 와 같이 행동하고 있다.

    IJulia.jl의 코드를 보았을 때, display를 부르는 것이 아니라, 보다 저레벨의 처리를 실시하고 있는 것 같아, 여기에 개입하는 것은 어려울 것 같다고 느꼈다.
    display(IJulia.InlineDisplay(), x) htps : // 기주 b. 코 m/주아아 g/이주아. jl/bぉb/마s r/src/인이네. jl#L93-L99

    셀 반환 값의 암시적 표시
    htps : // 기주 b. 코 m/주아아 g/이주아. jl/bぉb/4fd955 아후아 1/src/에ㄴㅎㅎ_레쿠에 st. jl#L128-L137

    좋은 웹페이지 즐겨찾기