Skip to content

Conversation

pearmini
Copy link
Collaborator

@pearmini pearmini commented Sep 10, 2025

/**
 * ============================================================================
 * =                   How to Create a Animals Isotype Chart?                 =
 * ============================================================================
 *
 * > Ref. https://observablehq.com/@observablehq/plot-isotype-chart
 *
 * Recho is suitable for Isotype Chart (Unit Chart), because it allows you to
 * encode data as characters easily. This sketch shows how to create a animals
 * isotype chart step by step. It's also a good example to show that Recho is
 * powerful in echoing intermediate results, helping you to understand the
 * data and the process of creating the chart.
 *
 * The final chart looks like below, which tells us about the live stock of
 * animals in Great Britain and United States. Compared to Great Britain, the
 * United States has more cattle and pigs, with pig showing the most dramatic
 * difference. In Great Britain, sheep are more prominent, which may related to
 * the country's geography and dietary traditions, such as the wool industry
 * and lamb consumption.
 */

//➜
//➜             Great Britain
//➜     pigs -| 🐖
//➜   cattle -| 🐄 🐄 🐄 🐄
//➜    sheep -| 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑
//➜
//➜             United States
//➜     pigs -| 🐖 🐖 🐖 🐖 🐖 🐖
//➜   cattle -| 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄
//➜    sheep -| 🐑 🐑 🐑 🐑 🐑 🐑 🐑
//➜
//➜ Live stock (millions)
//➜
echo(output);

/**
 * Next, let's dive into how `output` is generated.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *                          Preparing the data
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * First, we need to prepare the data. We're going to use the following dataset
 * to create the chart. It's a tiny tubular dataset, with each row representing
 * a animal in a country and the count of the animal.
 */

const data = [
  {animal: "pigs", country: "Great Britain", count: 1354979},
  {animal: "cattle", country: "Great Britain", count: 3962921},
  {animal: "sheep", country: "Great Britain", count: 10931215},
  {animal: "pigs", country: "United States", count: 6281935},
  {animal: "cattle", country: "United States", count: 9917873},
  {animal: "sheep", country: "United States", count: 7084151},
];

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *                            Importing D3
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Then we import D3 to help us with the data processing. In Recho, you can
 * typically use `recho.require(name)` to import an external library.
 *
 * > Ref. https://recho.dev/docs/libraries-imports
 * > Ref. https://d3js.org/
 */

const d3 = recho.require("d3");

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *                          Generating the bars
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * We'll get started with generating the bars. There are three main tasks here:
 *
 * 1. Mapping animals types to their corresponding emojis.
 * 2. Mapping the counts to the number of emojis.
 * 3. Generating the bars based on the emojis and the number.
 *
 * Here is the implementation:
 */

//➜ [ 0, 1, 2, 3, 4, 5 ]
const I = echo(d3.range(data.length));

//➜ { cattle: "🐄", sheep: "🐑", pigs: "🐖" }
const emoji = echo({cattle: "🐄", sheep: "🐑", pigs: "🐖"});

//➜ [ "🐖", "🐄", "🐑", "🐖", "🐄", "🐑" ]
const E = echo(data.map((d) => emoji[d.animal]));

//➜ [ 1, 4, 11, 6, 10, 7 ]
const V = echo(data.map((d) => Math.round(d.count / 1e6)));

//➜ [ "🐖 ", "🐄 🐄 🐄 🐄 ", "🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 ", "🐖 🐖 🐖 🐖 🐖 🐖 ", "🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 ", "🐑 🐑 🐑 🐑 🐑 🐑 🐑 " ]
const bars = echo(I.map((i) => `${E[i]} `.repeat(V[i])));

/** This is the chart we got so far. */

//➜ 🐖
//➜ 🐄 🐄 🐄 🐄
//➜ 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑
//➜ 🐖 🐖 🐖 🐖 🐖 🐖
//➜ 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄
//➜ 🐑 🐑 🐑 🐑 🐑 🐑 🐑
echo(bars.join("\n"));

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *                          Adding the labels
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Next step is to add the labels to the bars. We need to collect all the
 * animal types by a set, and compute a margin left to make sure the labels
 * are aligned. Then concatenate the labels to the bars with a separator: `-|`.
 */

//➜ [ "pigs", "cattle", "sheep" ]
const L = echo(Array.from(new Set(data.map((d) => d.animal))));

//➜ 6
const marginLeft = echo(d3.max(L, (d) => d.length));

//➜ [ "  pigs", "cattle", " sheep", "  pigs", "cattle", " sheep" ]
const labels = echo(data.map((d) => d.animal.padStart(marginLeft, " ")));

//➜ [ "    pigs -| 🐖 ", "  cattle -| 🐄 🐄 🐄 🐄 ", "   sheep -| 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 ", "    pigs -| 🐖 🐖 🐖 🐖 🐖 🐖 ", "  cattle -| 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 ", "   sheep -| 🐑 🐑 🐑 …
const rows = echo(I.map((i) => "  " + labels[i] + " -| " + bars[i]));

/** Now the chart looks like this. */

//➜     pigs -| 🐖
//➜   cattle -| 🐄 🐄 🐄 🐄
//➜    sheep -| 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑
//➜     pigs -| 🐖 🐖 🐖 🐖 🐖 🐖
//➜   cattle -| 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄
//➜    sheep -| 🐑 🐑 🐑 🐑 🐑 🐑 🐑
echo(rows.join("\n"));

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *                         Generating the titles
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Technically speaking, the chart is a facet chart, which means it contains
 * multiple charts. The first one is for Great Britain, and the second one is
 * for United States. In order to differentiate the two charts, we need to add
 * the titles and some spacing.
 */

//➜ 45
const width = echo(d3.max(rows, (d) => d.length));

//➜ [ "Great Britain", "United States" ]
const T = echo(Array.from(new Set(data.map((d) => d.country))));

//➜ [ "            Great Britain", "            United States" ]
const titles = echo(T.map((t) => t.padStart(Math.ceil(width / 2 + 2), " ")));

/**
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *                             Final output
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Finally, we can concatenate the titles, the rows, and the live stock caption
 * to get the final output!
 */

//➜
//➜             Great Britain
//➜     pigs -| 🐖
//➜   cattle -| 🐄 🐄 🐄 🐄
//➜    sheep -| 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑
//➜
//➜             United States
//➜     pigs -| 🐖 🐖 🐖 🐖 🐖 🐖
//➜   cattle -| 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄 🐄
//➜    sheep -| 🐑 🐑 🐑 🐑 🐑 🐑 🐑
//➜
//➜ Live stock (millions)
//➜
const output = echo(
  [
    " ",
    titles[0], // Great Britain
    ...rows.slice(0, 3),
    " ",
    titles[1], // United States
    ...rows.slice(3),
    " ",
    "Live stock (millions)", // Add a caption
    " ",
  ].join("\n"),
);

@pearmini pearmini force-pushed the example-animals-isotype-chart branch from 4025bd4 to 9ee246e Compare September 10, 2025 12:12
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Sep 10, 2025

Deploying recho with  Cloudflare Pages  Cloudflare Pages

Latest commit: ed7d351
Status: ✅  Deploy successful!
Preview URL: https://be713f1c.recho.pages.dev
Branch Preview URL: https://example-animals-isotype-char.recho.pages.dev

View logs

@pearmini pearmini merged commit 751bfc0 into main Sep 10, 2025
2 checks passed
@pearmini pearmini deleted the example-animals-isotype-chart branch September 10, 2025 12:21
@pearmini pearmini changed the title Add animals isotype chart [Example] Animals Isotype Chart Sep 10, 2025
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

Successfully merging this pull request may close these issues.

1 participant