Public
Edited
Sep 6, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Customize the plot of sales by date
Plot.plot({
marks: [Plot.rectY(data, Plot.binX({ y: "sum" }, { x: "date", y: "value" }))],
marginLeft: 50, // space to the left of the chart
marginBottom: 50, // space below the chart
insetBottom: 33, // space between the x-axis and the marks
insetLeft: 29, // space between the y-axis and the marks
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Inputs.table(data)
Insert cell
Insert cell
Insert cell
Insert cell
import {toc} from "@nebrius/indented-toc"
Insert cell
import {
createDemo,
intro,
plotWidth,
dataDescription,
welcomeBox,
download,
inputStyles,
deck
} with { data } from "@observablehq/cheatsheet-utilities";
Insert cell
Insert cell
// Purchase event data -- queried from this notebook using this query:
// https://observablehq.com/@observablehq/bigquery-e-commerce-public-data
/* select * from events
join items on events.item_id = items.id
where type = 'purchase' */
events = FileAttachment("purchase_data.csv").csv({ typed: true })
Insert cell
// Aggregate the data
data = aq.from(events)
.derive({date: aq.escape(d => d3.utcDay(d.date))})
.groupby("date", "brand")
.rollup({value: d => aq.op.sum(d.price_in_usd), count: aq.op.count()})
.orderby("date", "brand")
.objects()
Insert cell
Insert cell
// Get the configuration from the inputs
getConfig = (config) => {
let ret = {};
// parse each value
Object.entries(config)
.filter(([key, value]) => value !== undefined)
.map(
([key, value]) =>
(ret[key] = value[0] === "[" ? JSON.parse(value) : value)
);
const stringified = JSON.stringify(ret, null)
.replace(/,/g, ",\n\t")
.replace(/:/g, ": ")
.replace(/"([^"]+)":/g, "$1:"); // removing param quotes
return stringified;
}
Insert cell
introParagraph = () => htl.html`<p style="margin-top:0px"><a href ="https://observablehq.com/@observablehq/plot?collection=@observablehq/plot" target="_blank">Observable Plot</a> provides granular control over the colors, fonts, and spacing in your visualizations. It also enables the creation of small multiples through its <a href="https://observablehq.com/@observablehq/plot-facets?collection=@observablehq/plot" target="_blank">facet</a> feature.</p>`
Insert cell
Insert cell
layout = ({
controls: [
{ type: "text", value: "Plot.plot({" },
{ type: "text", value: "// size", indent: 2 },
{ param: "height", type: "range", value: 400, min: 200, max: 600, step: 1 },
{
param: "width",
type: "range",
value: plotWidth - 100,
min: 300,
max: plotWidth,
step: 1
},
{ type: "text", value: "// space around", indent: 2 },
{
param: "marginLeft",
type: "range",
value: 50,
min: 0,
max: 100,
step: 1
},
{
param: "marginRight",
type: "range",
value: 50,
min: 0,
max: 100,
step: 1
},
{ param: "marginTop", type: "range", value: 50, min: 0, max: 100, step: 1 },
{
param: "marginBottom",
type: "range",
value: 50,
min: 0,
max: 100,
step: 1
},
{ type: "text", value: "// space within", indent: 2 },
{ param: "insetTop", type: "range", value: 0, min: 0, max: 100, step: 1 },
{
param: "insetBottom",
type: "range",
value: 0,
min: 0,
max: 100,
step: 1
},
{ param: "insetLeft", type: "range", value: 0, min: 0, max: 100, step: 1 },
{ param: "insetRight", type: "range", value: 0, min: 0, max: 100, step: 1 },
{ type: "text", value: "})" }
],
plot: (config) => `Plot.plot({
marks: [
Plot.rectY(data, Plot.binX({ y: "sum" }, { x: "date", y: "value" })),
Plot.frame({ stroke: "#d3d3d3" })
],
${getConfig(config).replace(/[{}]/g, "")}
})`
})
Insert cell
styles = ({
controls: [
{ type: "text", value: "Plot.plot({" },
{ type: "text", value: "style: {", indent: 1 },
{ param: "backgroundColor", type: "color", value: "#7e9a9a" },
{ param: "color", type: "color", value: "#e0f5ee" },
{
param: "fontFamily",
type: "select",
options: ["system-ui", "sans-serif", "monospace", "serif"]
},
{ param: "fontSize", type: "range", min: 5, max: 15, value: 9, step: 1 },
{
param: "overflow",
type: "radio",
options: ["hidden", "visible"],
value: "visible"
},
{ type: "text", value: "}})" }
],
plot: (config) => `Plot.plot({
marks: [Plot.rectY(data, Plot.binX({ y: "sum" }, { x: "date", y: "value" }))],
style: {
backgroundColor: "${config.backgroundColor}",
color: "${config.color}",
fontFamily: "${config.fontFamily}",
fontSize: "${config.fontSize}px",
overflow: "${config.overflow}"
},
width: ${plotWidth},
margin: 50
})`
})
Insert cell
facets = ({
controls: [
{ type: "text", value: "Plot.plot({" },
{ type: "text", value: "facet: {", indent: 1 },
{ param: "data", value: "data" },
{
param: "x",
type: "select",
value: "brand",
options: new Map([
["brand", "brand"],
["d => d3.utcMonth(d.date)", (d) => d3.utcMonth(d.date)],
["d => d3.utcYear(d.date)", (d) => d3.utcYear(d.date)],
["no faceting", ""]
])
},
{
param: "y",
type: "select",
value: "",
options: new Map([
["brand", "brand"],
["d => d3.utcMonth(d.date)", (d) => d3.utcMonth(d.date)],
["d => d3.utcYear(d.date)", (d) => d3.utcYear(d.date)],
["no faceting", ""]
])
},
{
param: "marginRight",
type: "range",
value: 50,
min: 0,
max: 100,
step: 1
},
{
param: "marginLeft",
type: "range",
value: 50,
min: 0,
max: 100,
step: 1
},
{ type: "text", value: "},", indent: 1 },

// fx
{ type: "text", value: "fx: {", indent: 1 },
{ param: "insetLeft", type: "range", value: 10, min: 0, max: 100, step: 1 },
{
param: "insetRight",
type: "range",
value: 10,
min: 0,
max: 100,
step: 1
},
{
param: "fxPadding",
label: "padding",
type: "range",
value: 0.1,
min: 0,
max: 1,
step: 0.01
},
{ param: "fxLabel", label: "label", type: "textInput" },
{
param: "fxTickFormat",
label: "tickFormat",
type: "select",
value: "",
options: new Map([
["default", ""],
["d => d.toUpperCase()", (d) => d.toUpperCase()],
["d3.utcFormat('%B')", (d) => d3.utcFormat("%B")(d)],
["d3.utcFormat('%Y')", (d) => d3.utcFormat("%Y")(d)]
])
},
{ type: "text", value: "},", indent: 1 },

// fy
{ type: "text", value: "fy: {", indent: 1 },
{ param: "insetTop", type: "range", value: 10, min: 0, max: 100, step: 1 },
{
param: "insetBottom",
type: "range",
value: 10,
min: 0,
max: 100,
step: 1
},
{
param: "fyPadding",
label: "padding",
type: "range",
value: 0.01,
min: 0,
max: 1,
step: 0.1
},
{ param: "fyLabel", label: "label", type: "textInput" },
{
param: "fyTickFormat",
label: "tickFormat",
type: "select",
value: "",
options: new Map([
["default", ""],
["d => d.toUpperCase()", (d) => d.toUpperCase()],
["d3.utcFormat('%B')", (d) => d3.utcFormat("%B")(d)],
["d3.utcFormat('%Y')", (d) => d3.utcFormat("%Y")(d)]
])
},
{ type: "text", value: "}})" },

// Extra options
{ type: "text", value: "\n\n// additional options" },
{
param: "background",
label: "show full histogram backround",
type: "toggle",
value: true
},
{ param: "frame", label: "show frames", type: "toggle", value: true }
],
plot: (config) => {
// Construct the marks option with the proper indentation
const rects = `Plot.rectY(data, Plot.binX({ y: "sum" }, { x: "date", y: "value" }))`
const backgroundRects = `Plot.rectY(
data,
Plot.binX(
{ y: "sum" },
{ x: "date", y: "value", fillOpacity: 0.1, facet: "exclude" }
)
)`
const frames = `Plot.frame()`
let marks = ''
if(!config.background && !config.frame) marks = `marks: [${rects}]`;
else {
marks = `marks: [\n\t\t${rects}`
if(config.background) marks += `,\n\t\t${backgroundRects}`
if(config.frame) marks += `,\n\t\t${frames}`
marks += `\n\t]`
}
return `Plot.plot({
${marks},
facet: {
data: data,
x: ${typeof config.x === "string" ? `"${config.x}"` : config.x},
y: ${typeof config.y === "string" ? `"${config.y}"` : config.y},
marginRight: ${config.marginRight},
marginLeft: ${config.marginLeft}
},
fx: {
insetLeft: ${config.insetLeft},
insetRight: ${config.insetRight},
padding: ${config.fxPadding}${config.fxLabel ? `,\n\t\tlabel: "${config.fxLabel}"` : ""}${config.fxTickFormat ? `,\n\t\ttickFormat: ${config.fxTickFormat}` : ""}
},
fy: {
insetTop: ${config.insetTop},
insetBottom: ${config.insetBottom},
padding: ${config.fyPadding}${config.fyLabel ? `,\n\t\tlabel: "${config.fyLabel}"` : ""}${config.fyTickFormat ? `,\n\t\ttickFormat: ${config.fyTickFormat}` : ""}
},
width: ${plotWidth}
})`}})
Insert cell
Insert cell
<style>
.code_form {
width: 300px;
}
label {
width: 120px !important
}
</style>
Insert cell
inputStyles
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more