Generating Charts in Pure Ruby Without JavaScript

May 7, 2026

Modern chart rendering usually assumes a browser, a JavaScript runtime, or a frontend stack.

But many Ruby applications do not actually need interactive dashboards.

They need deterministic image generation.

Things like:

  • scheduled reports
  • PDF exports
  • transactional emails
  • admin dashboards
  • analytics snapshots
  • CI metrics
  • server-side rendering pipelines

That was the motivation behind building RubyCharts: a lightweight chart rendering library written for backend-oriented Ruby workflows.

The project is still under active development, but the core idea is already working: generate PNG charts directly from Ruby using native rendering primitives.

The rendering backend is powered by ruby-libgd.

Tokyo Topographic Map
Built for Ruby on Rails

Build Maps Without
Google APIs

Generate beautiful production-ready maps directly from your Rails backend. Fast rendering, zero external dependencies, full control.

✓ No API fees ✓ Self-hosted ✓ Rails Native ✓ Fast Rendering
Why developers switch
Replace expensive map stacks.

Stop relying on third-party map billing and bloated JS libraries. Render static or dynamic maps directly in Ruby.

Try It Now
Tokyo MapView Demo

The Goal

Article content

The goal was not to create another browser-based visualization framework.

The goal was:

  • no JavaScript runtime
  • no headless browser
  • no external rendering service
  • no ImageMagick shelling
  • simple Ruby API
  • static image generation
  • lightweight server-side rendering

The current API is intentionally small:

RubyCharts.from_csv('sales.csv')
.type(:pie)
.title('Product Sales Distribution')
.subtitle('Q1 2024')
.save_png('output/chart.png')

Data can currently be loaded from:

  • CSV
  • YAML
  • Ruby hashes
  • XLSX

Supported chart types include:

  • pie charts
  • vertical bar charts
  • horizontal bar charts
  • line charts

Why Native Rendering?

One of the most interesting parts of this project is the rendering layer itself.

Instead of delegating image generation to external tools, the charts are rendered directly through GD using a Ruby C extension.

That means the rendering pipeline stays fully inside the Ruby process.

The underlying graphics layer comes from:

This enables direct access to:

  • PNG encoding
  • JPEG encoding
  • WebP encoding
  • drawing primitives
  • alpha blending
  • in-memory image generation

For example:

static VALUE gd_image_to_png(VALUE self) {
gd_image_wrapper *wrap;
TypedData_Get_Struct(self, gd_image_wrapper, &gd_image_type, wrap);
int size = 0;
void *data = gdImagePngPtr(wrap->img, &size);
VALUE str = rb_str_new((const char*)data, size);
gdFree(data);
return str;
}

That small method opens interesting integration possibilities for Ruby applications.

Instead of writing files to disk, charts can be streamed directly from memory.

Example:

send_data chart.to_png, type: 'image/png'

That becomes useful for:

  • Rails controllers
  • APIs
  • background jobs
  • email attachments
  • ActiveStorage uploads
  • PDF generation

The Rendering Pipeline

Internally, the library is organized around a small rendering pipeline:

Loader → Builder DSL → Chart Renderer → GD Backend → PNG/JPEG/WebP

The current architecture separates:

  • data ingestion
  • chart configuration
  • chart rendering
  • image encoding

The public API intentionally hides the lower-level drawing primitives.

Users interact with charts at a higher abstraction level:

RubyCharts.from_yaml('data.yml')
.type(:line)
.title('Monthly Revenue')
.save_png('line_chart.png')

While internally, the library handles:

  • scaling
  • coordinate calculations
  • text rendering
  • color allocation
  • image composition
  • output encoding

Why This Matters for Ruby

Ruby has excellent tooling for:

  • web applications
  • APIs
  • background jobs
  • automation

But lightweight native graphics tooling is still relatively uncommon in the ecosystem.

Many existing chart solutions depend on:

  • browser runtimes
  • Node.js
  • JavaScript wrappers
  • external chart services

RubyCharts explores a different direction: backend-native rendering infrastructure.

That is particularly useful for:

  • reporting systems
  • offline environments
  • automated exports
  • low-resource deployments
  • deterministic rendering workflows

Current Status

The project is still early.

Some planned areas include:

  • SVG backend support
  • theme systems
  • better layout engines
  • legend improvements
  • font management
  • scaling abstractions
  • additional chart types

But the core rendering pipeline is already producing usable charts.

Coming Soon

RubyCharts is currently being prepared for a public release.

The graphics backend powering the renderer is already available here:

ruby-libgd on GitHub

If you are interested in:

  • Ruby native extensions
  • server-side graphics
  • backend rendering pipelines
  • lightweight infrastructure tooling

this project will probably be worth following over the next few weeks.

Article content

Leave a comment