npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

jsx-tikzcd

v0.5.1

Published

Render tikzcd diagrams with JSX.

Downloads

48

Readme

jsx-tikzcd Build Status

Render tikzcd diagrams with JSX.

Table of Contents

Introduction

tikzcd is a powerful LaTeX package that can draw beautiful diagrams used in mathematics, especially category theory. However, its syntax is primarily based on the appearance, not the semantics, which makes it difficult to, say, change the position of a single node without having to redefine the edges.

jsx-tikzcd can turn a simple, semantic JSX tree consisting of nodes and edges into tikzcd code. The following JSX

// JSX code

<Diagram>
    <Node key="prod" position={[0, 0]} value="X\times_Z Y" />
    <Node key="a" position={[1, 0]} value="X" />
    <Node key="b" position={[0, 1]} value="Y" />
    <Node key="base" position={[1, 1]} value="Z" />

    <Edge from="a" to="base" />
    <Edge from="b" to="base" />
    <Edge from="prod" to="a" value="p_1" />
    <Edge from="prod" to="b" value="p_2" alt />
</Diagram>

yields

% LaTeX code

\begin{tikzcd}
X\times_Z Y \arrow[r, "p_1"] \arrow[d, "p_2"'] & X \arrow[d] \\
Y \arrow[r] & Z
\end{tikzcd}

which renders into

Demo

Getting Started

Installation

You can install jsx-tikzcd using npm:

npm install jsx-tikzcd

Set Up

Make sure you have JSX set up correctly in Babel:

{
    "plugins": [
        ["transform-react-jsx", {"pragma": "h"}]
    ]
}

Render

Then you can render TikZ diagrams like this:

import {h, render, Diagram, Node, Edge} from 'jsx-tikzcd'

let tex = render(
    <Diagram>
        <Node key="prod" position={[0, 0]} value="X\times_Z Y" />
        <Node key="a" position={[1, 0]} value="X" />
        <Node key="b" position={[0, 1]} value="Y" />
        <Node key="base" position={[1, 1]} value="Z" />

        <Edge from="a" to="base" />
        <Edge from="b" to="base" />
        <Edge from="prod" to="a" value="p_1" />
        <Edge from="prod" to="b" value="p_2" alt />
    </Diagram>
)

Components

You can define your own components and use them to make higher-order components just like in React.

import {h, render, Component, Diagram, Node, Edge} from 'jsx-tikzcd'

class Arrow extends Component {
    render() {
        if (this.props.children.length < 2) return

        let [x, y] = this.props.position || [0, 0]
        let [dx, dy] = this.props.direction || [1, 0]
        let [a, b, ] = this.props.children

        return <Diagram>
            <Node {...a.props} position={[x, y]} />
            <Node {...b.props} position={[x + dx, y + dy]} />

            <Edge from={a.key} to={b.key} />
        </Diagram>
    }
}

let tex = render(
    <Diagram>
        <Arrow>
            <Node key="x" value="X" />
            <Node key="y" value="Y" />
        </Arrow>

        <Node key="z" value="Z" position={[2, 0]} />
        <Edge from="y" to="z" />
    </Diagram>
)

jsx-tikzcd doesn't support state and tracking state changes, so every component is a pure component and can be written as a function as well:

const Arrow = function(props) {
    if (props.children.length < 2) return

    let [x, y] = props.position || [0, 0]
    let [dx, dy] = props.direction || [1, 0]
    let [a, b, ] = props.children

    return <Diagram>
        <Node {...a.props} position={[x, y]} />
        <Node {...b.props} position={[x + dx, y + dy]} />

        <Edge from={a.key} to={b.key} />
    </Diagram>
}

Gluing

Nodes with the same key will be merged and collapsed into one single node. This is useful to glue multiple sub components together.

let tex = render(
    <Diagram>
        <Arrow>
            <Node key="x" value="X" />
            <Node key="y" value="Y" />
        </Arrow>

        {/* Gluing at y */}

        <Arrow position={[1, 0]}>
            <Node key="y" />
            <Node key="z" value="Z" />
        </Arrow>
    </Diagram>
)

// \begin{tikzcd}
// X \arrow[r] & Y \arrow[r] & Z
// \end{tikzcd}

If there are conflicting attributes, the one that was defined last is used, i.e. attributes that come after will overwrite attributes that came before. Keep in mind that edges are not glued; you can define multiple edges between two nodes.

Duality

In category theory, there's this concept of an opposite category, in which every arrow of a diagram is reversed. It's possible to automate this process in jsx-tikzcd by adding the attribute co to a Diagram:

let tex = render(
    <Diagram co>
        <Arrow>
            <Node key="x" value="X" />
            <Node key="y" value="Y" />
        </Arrow>

        <Arrow position={[1, 0]}>
            <Node key="y" />
            <Node key="z" value="Z" />
        </Arrow>
    </Diagram>
)

// \begin{tikzcd}
// X & Y \arrow[l] & Z \arrow[l]
// \end{tikzcd}

Alternatively, you can use the corender function of jsx-tikzcd:

import {h, corender, Diagram, Node, Edge} from 'jsx-tikzcd'

let tex = corender(
    <Diagram>
        <Arrow>
            <Node key="x" value="X" />
            <Node key="y" value="Y" />
        </Arrow>

        <Arrow position={[1, 0]}>
            <Node key="y" />
            <Node key="z" value="Z" />
        </Arrow>
    </Diagram>
)

Documentation

render and corender

Arguments

  • vnode <Diagram/> - The diagram to render
  • options <Object> (optional)
    • align <Boolean> - Determines whether the generated code will vertically align at &. Default: false

Returns a string which contains the corresponding LaTeX code to the given diagram.

<Diagram/>

Props

  • co <Boolean> (optional) - Determines whether to reverse all edges
  • options <String> (optional) - tikzcd environment options

These attributes only work in the root node, i.e. the node that's passed to render or corender.

<Node/>

Props

  • key <String>
  • position <Integer[]> - Has the form [x, y], negative integers are also allowed
  • value <String> (optional) - LaTeX label

<Edge/>

Props

  • from <String> - Key of the start node
  • to <String> - Key of the end node
  • value <String> (optional) - LaTeX label
  • labelPosition <String> (optional) - One of "left", "right", and "inside"
  • alt <Boolean> (optional) - Determines whether the label is positioned on the other side of the arrow
  • args <String[]> (optional) - Additional tikzcd arguments of edge, e.g. "hook", "two heads", etc.

Related

  • tikzcd-editor - A simple visual editor for creating commutative diagrams.