Interactive Line & Area Charts in R with echarts4r

Add hover tooltips, a zoom slider, area fills, and multiple series to a ggplot-style line chart

Data Visualization

Turn a static ggplot2 line chart into an interactive one with echarts4r — add hover tooltips, a zoom slider for long time series, area fills, and multiple series you can toggle in the legend, all from a familiar pipe workflow. Each chart loads on demand so the page stays fast.

Published

July 9, 2026

Modified

July 9, 2026

TipKey takeaways
  • echarts4r wraps Apache ECharts, a free, open-source JavaScript charting library, in a tidy R pipe — e_charts() starts a chart, e_line() adds a line.
  • Lines are the natural fit for a trend across an ordered or continuous x (usually time); interactivity adds hover tooltips, a zoom slider for long series, area fills, and multiple series you toggle in the legend.
  • On this page every interactive chart sits behind a static poster you click to load — the heavy chart library only downloads on demand, so the page stays within the mobile performance budget.
  • The static poster is a plain ggplot2 chart, produced by code you can copy and run — the interactive version is the same data, made explorable.

Introduction

You already make line charts with ggplot2: geom_line(), a colour, a date on the x-axis, done. That static chart is perfect for a report or a paper. But sometimes you want the reader to explore it — read the exact value on hover, zoom into one year of a long series, or toggle a group on and off. That is where echarts4r comes in: it brings Apache ECharts — a mature, free, open-source charting library — into R with a pipe workflow that feels familiar if you know the tidyverse.

This lesson builds the same line chart twice: first as a static ggplot2 figure (the reproducible baseline, and the fast-loading poster you see on the page), then as an interactive echarts4r widget you load with a click. We start with a single line, add a zoom slider and an area fill, then plot several series at once.

NoteWhy each chart loads on click

An interactive ECharts widget ships about 1 MB of JavaScript and draws to an HTML canvas (the browser’s pixel-drawing surface). Loading several at once would make the page slow on a phone — it would blow the Core Web Vitals budget (Google’s page-speed metrics, of which LCP, the time to paint the largest element, is the one a heavy widget hurts most). So on this page each interactive chart is represented by a static image first; clicking ▶ Load interactive chart swaps in the real, fully interactive echarts4r widget. You get the speed of a static page and the full interactivity on demand. In your own report or Shiny app you would simply print the widget directly — the code is identical.

The static baseline: a ggplot2 line chart

We will chart monthly airline passengers from the built-in AirPassengers series — 144 monthly totals from 1949 to 1960, a classic rising-with-seasonality trend. First, turn the time series into a plain data frame with base R and draw a line with ggplot2. This static figure is the reproducible baseline — and, on this page, the main image the page loads first.

library(ggplot2)

# Turn the built-in time series into a data frame (base R — no dplyr needed)
ap <- data.frame(
  month      = seq_along(AirPassengers),   # 1..144, one per month
  passengers = as.numeric(AirPassengers)
)

ggplot(ap, aes(month, passengers)) +
  geom_line(colour = "#3a86d4", linewidth = 1) +
  labs(x = "Month (1 = Jan 1949)", y = "Passengers (thousands)",
       title = "Monthly airline passengers, 1949–1960") +
  theme_minimal(base_size = 13)

A line chart of monthly airline passenger totals from 1949 to 1960, rising steadily with a seasonal wobble, in brand azure.

The single line uses the brand azure #3a86d4, and theme_minimal() keeps it clean. This is a publication-ready chart. Now let’s make the same trend explorable.

Your first interactive line chart

echarts4r reads a data frame, you name the x column in e_charts(), then add a line with e_line(). The pipe (|>) chains the steps, exactly like adding layers in ggplot2. Because this is a long series (144 points), we also add a zoom slider with e_datazoom() so the reader can focus on any period. We assign the chart to basic rather than printing it inline, so the page stays light — then load it behind the poster below.

library(echarts4r)

ap <- data.frame(
  month      = seq_along(AirPassengers),
  passengers = as.numeric(AirPassengers)
)

basic <- ap |>
  e_charts(month) |>                       # the x axis (ordered months)
  e_line(passengers, name = "Passengers") |>  # a line series from the passengers column
  e_color("#3a86d4") |>                    # brand azure, matching the static chart
  e_tooltip() |>                           # show a tooltip on hover
  e_datazoom(type = "slider") |>           # a draggable zoom slider below the axis
  e_legend(show = FALSE)                   # one series — no legend needed

Read the pipe top to bottom: start a chart on month, add a passengers line named “Passengers”, colour it azure, enable hover tooltips, and add a slider. e_datazoom(type = "slider") is the interaction a static PNG cannot give you — drag its handles to zoom into a single year. Now save the widget and show it behind a poster.

Line chart of monthly airline passengers rising from 1949 to 1960. Hover the line to read the passenger count for any month; drag the slider to zoom into a period.

Hover the line and ECharts shows the exact value in a floating tooltip; drag the slider handles to focus on one stretch of months — the interactions you cannot get from a static PNG. Everything else is the same data and the same azure palette.

Filling the area under the line

When the story is a growing total over time, filling the region under the line makes the trend read at a glance. echarts4r does this with e_area() — the same call as e_line(), just filled. Swap one function and keep the rest of the pipe.

ap <- data.frame(
  month      = seq_along(AirPassengers),
  passengers = as.numeric(AirPassengers)
)

area <- ap |>
  e_charts(month) |>
  e_area(passengers, name = "Passengers") |>  # e_area fills under the line
  e_color("#3a86d4") |>
  e_tooltip() |>
  e_datazoom(type = "slider") |>
  e_legend(show = FALSE)

e_area() draws the same line but shades everything beneath it, so the rising volume is unmistakable. Use it for a single accumulating quantity; for comparing several series a plain line (next section) usually reads more clearly than stacked fills.

Area chart of monthly airline passengers with the region under the line filled. The filled area emphasises the growing trend over time.

The loaded widget keeps the hover tooltip and the zoom slider — only the fill changed. That is the payoff of the pipe grammar: one function swap moves you between chart types with everything else intact.

Multiple series: one line per group

Lines really earn their interactivity when you compare several series at once. Here we track mean chick weight over time by diet, from the built-in ChickWeight dataset. The idiom is base R: average the weights per time point and diet with aggregate(), reshape to a wide table (one column per diet) with base reshape(), then add one e_line() per diet. The legend is interactive — click a diet name in the rendered chart to toggle it.

# Mean weight per time point x diet (base R — no dplyr)
cw <- aggregate(weight ~ Time + Diet, data = ChickWeight, FUN = mean)

# Reshape long -> wide: one row per Time, one column per Diet
w <- reshape(cw, idvar = "Time", timevar = "Diet", direction = "wide")
names(w) <- c("Time", "Diet1", "Diet2", "Diet3", "Diet4")

multi <- w |>
  e_charts(Time) |>
  e_line(Diet1) |>
  e_line(Diet2) |>
  e_line(Diet3) |>
  e_line(Diet4) |>
  e_color(c("#440154", "#31688e", "#35b779", "#fde725")) |>  # viridis, colourblind-safe
  e_tooltip(trigger = "axis")                                 # one tooltip for all series

Each diet gets its own e_line() call and its own colour from the e_color() vector. e_tooltip(trigger = "axis") shows all four values at the hovered time point, so you can compare diets directly. Save it and show the poster.

Four lines showing mean chick weight over time, one per diet. Hover a time point to compare all four diets; click a legend entry to toggle a diet.

In the loaded chart, click a diet in the legend to hide or show its line — the axis rescales automatically. That legend toggle is a genuinely interactive affordance a static figure can’t offer.

The single-line and area charts plot AirPassengers: 144 rows of month (1–144, one per month from January 1949) and passengers (monthly totals in thousands). The multi-series chart uses mean chick weight by time and diet:

Mean chick weight (g) at each measurement time, by diet.
Time Diet1 Diet2 Diet3 Diet4
0 41.4 40.7 40.8 41.0
2 47.2 49.4 50.4 51.8
4 56.5 59.8 62.2 64.5
6 66.8 75.4 77.9 83.9
8 79.7 91.7 98.4 105.6
10 93.1 108.5 117.1 126.0
12 108.5 131.3 144.4 151.4
14 123.4 141.9 164.5 161.8
16 144.6 164.7 197.4 182.0
18 158.9 187.7 233.1 202.9
20 170.4 205.6 258.9 233.9
21 177.8 214.7 270.3 238.6

Common issues

The chart doesn’t appear / the page just shows the poster. That’s by design on this site — click ▶ Load interactive chart and the real widget loads. In your own document, print(basic) (or letting basic be the last line of a chunk) renders the widget directly with no poster.

My multiple lines all come out the same colour, or the legend is empty. Each series needs its own e_line() call on its own column, and the data must be wide (one column per group). If your data is long (a group column plus a value column), reshape it first with reshape(..., direction = "wide") as in the lesson, then add one e_line() per resulting column.

My x-axis treats time as categories, not a continuous scale. echarts4r infers the axis type from the column. A numeric x (like month here) gives a continuous value axis; a character or factor x gives a category axis. Keep the x column numeric (or a real Date) for an evenly spaced time axis.

Frequently asked questions

Yes. echarts4r is released under the Apache 2.0 licence and wraps Apache ECharts, which is also Apache 2.0 — a permissive, free, open-source licence with no per-site or commercial fee. You can use it in reports, dashboards, and public sites without a paid licence.

They draw the same line; e_area() also fills the region beneath it. Use e_area() for a single accumulating quantity where the filled volume tells the story, and e_line() when you compare several series (overlapping fills get muddy). Everything else in the pipe — tooltip, colour, zoom — stays the same.

echarts4r’s tidy idiom is group_by(), but you can stay in base R: reshape your data to wide with reshape(long, idvar = "x", timevar = "group", direction = "wide") so each group becomes its own column, then add one e_line() per column. That is exactly the multi-series pattern in this lesson.

Add e_datazoom(type = "slider") whenever the series is long enough that individual points crowd together — a multi-year monthly or daily series, for example. For a short series (a handful of points) the slider adds clutter without benefit, so leave it off.

ggiraph makes your existing ggplot2 line chart interactive by rendering it as SVG, so the look is identical to ggplot2 and the widget is lightweight. echarts4r draws with a different engine (Apache ECharts on an HTML canvas) that offers richer built-in interactions — a zoom slider, animated transitions, legend toggles — at the cost of a larger JavaScript payload. Use ggiraph for your publication ggplot look with light interactivity; reach for echarts4r when you need those richer built-in controls.

Test your understanding

Using the built-in EuStockMarkets dataset, plot two indices — the DAX and the FTSE — as separate lines over time, azure and amber, with an axis-triggered tooltip and a zoom slider. Assign the chart to a variable and print it to view.

EuStockMarkets is a multivariate time series. Turn it into a data frame first, add a day index, then chain e_charts(day) with one e_line() per index column. Colour with e_color(c("#3a86d4", "#f5a524")), the tooltip with e_tooltip(trigger = "axis"), and the slider with e_datazoom(type = "slider").

library(echarts4r)

# Base-R data prep: matrix -> data frame + a day index
eu <- as.data.frame(EuStockMarkets)
eu$day <- seq_len(nrow(eu))

eu |>
  e_charts(day) |>
  e_line(DAX) |>
  e_line(FTSE) |>
  e_color(c("#3a86d4", "#f5a524")) |>
  e_tooltip(trigger = "axis") |>
  e_datazoom(type = "slider")

Two e_line() calls give two series; trigger = "axis" shows both values at the hovered day, and the slider lets you zoom into any stretch of trading days.

Quick check. You want the region under a single time series filled to emphasise its growth. Do you reach for e_line() or e_area()?

e_area(). It draws the same line as e_line() but shades everything beneath it, so a growing total reads at a glance. Swap e_line() for e_area() and keep the rest of the pipe unchanged.

Conclusion

echarts4r turns a familiar line chart into an explorable one: e_charts() sets the x axis, e_line() (or e_area()) adds the trend, and a short pipe adds a hover tooltip, a zoom slider, and multiple togglable series. The static ggplot2 poster keeps the page fast; one click reveals the full interactive chart. Every result on this page was produced by the code shown — copy any block and run it to reproduce them. From here, the same pipe grammar extends to bar, scatter, and many other chart types.

Reuse

Citation

BibTeX citation:
@online{2026,
  author = {},
  title = {Interactive {Line} \& {Area} {Charts} in {R} with Echarts4r},
  date = {2026-07-09},
  url = {https://www.datanovia.com/learn/data-visualization/echarts4r/interactive-line-charts},
  langid = {en}
}
For attribution, please cite this work as:
“Interactive Line & Area Charts in R with Echarts4r.” 2026. July 9. https://www.datanovia.com/learn/data-visualization/echarts4r/interactive-line-charts.