← All ivy-nodes
IVYXSTUDIO · IVY NODE
C

Chart Image

ivy.node.chart-image · v0.1.0

ivyx✓

Draws a bar or line chart of two columns of rows and writes it as a PNG file. Returns the file's path and size, so a report can link the image; needs plotly and kaleido.

#chart#plot#png#report

Inputs

FieldTypeDescription
rowsrequiredarrayThe rows to chart.
xstringThe column on the x axis. The first column when omitted.
ystringThe column on the y axis. The first numeric column when omitted.
kindstringBar or line chart.
titlestringThe chart title.
pathrequiredstringWhere to write the PNG.
widthintegerWidth in pixels.
heightintegerHeight in pixels.

Outputs

FieldTypeDescription
pathrequiredstringThe absolute path of the PNG written.
size_bytesrequiredintegerThe file's size.
xstringThe column drawn on the x axis.
ystringThe column drawn on the y axis.

Source

python

inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]

import os
import plotly.express as px

rows = inp["rows"]
kind = inp.get("kind", "bar")
title = inp.get("title", "")
path = inp["path"]
width = int(inp.get("width", 900))
height = int(inp.get("height", 500))

if kind not in ("bar", "line"):
    raise ValueError("kind must be bar or line")
if not rows:
    raise ValueError("There are no rows to chart.")
# x defaults to the first column and y to the first numeric one after it: an
# agent's chart step rarely knows the name an aggregate gave its column.
columns = list(rows[0].keys())
x = inp.get("x") or columns[0]
numeric = [c for c in columns if c != x and isinstance(rows[0].get(c), (int, float)) and not isinstance(rows[0].get(c), bool)]
y = inp.get("y") or (numeric[0] if numeric else None)
if y is None:
    raise ValueError("No numeric column to chart; name one as y.")
# A named axis the rows lack is taken from them only when there is one
# choice: one text column for x, one numeric for y. A plan read "x: month"
# over rows whose key kept its source name, date. Anything less certain is
# refused with the columns there are; the output names what was drawn.
texts = [c for c in columns if not isinstance(rows[0].get(c), (int, float)) or isinstance(rows[0].get(c), bool)]
numbers = [c for c in columns if c not in texts]
if x not in rows[0] and len(texts) == 1:
    x = texts[0]
if y not in rows[0] and len([c for c in numbers if c != x]) == 1:
    y = [c for c in numbers if c != x][0]
missing = [c for c in (x, y) if c not in rows[0]]
if missing:
    raise ValueError(f"The rows have no column {missing[0]!r}; they have {', '.join(columns)}.")
draw = px.bar if kind == "bar" else px.line
figure = draw({x: [r.get(x) for r in rows], y: [r.get(y) for r in rows]}, x=x, y=y, title=title)
figure.update_layout(width=width, height=height)
# The x values are labels as written: "2026-07" read as a date put "Jun 28"
# and "Jul 12" under a monthly bar chart.
figure.update_xaxes(type="category")
folder = os.path.dirname(os.path.abspath(path))
os.makedirs(folder, exist_ok=True)
figure.write_image(path, format="png")

out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["path"] = os.path.abspath(path)
out["size_bytes"] = os.path.getsize(path)
out["x"] = x
out["y"] = y

Tests

Requires: python:3.9, plotly, kaleido

  • bar-png

    Two months of sales draw a bar chart of a few kilobytes.

  • named-axes-it-lacks

    Axes the rows lack are taken from the one text and one number column there are.

  • default-axes

    With no axes named, the first column and the first number are drawn.

  • missing-column

    A column the rows do not have is named.