Line Chart

A line chart draws a single continuous line through (timestamp, value) points to show how one number changes over time. Use it when the value is a continuous quantity (price, yield, latency, count) sampled at ordered timestamps.

Line charts work well with TVL’s by argument, which partitions one input table into one line per unique value. That lets you overlay several symbols or strategies on the same axis without manually splitting the table.

What are line charts useful for?

  • Showing trend over time: A single line strips away everything but the trajectory, which is what you usually want for a quick “is it going up or down” read.
  • Comparing multiple series: With by you can overlay several groups on the same axis and visually compare their levels and slopes.
  • Highlighting state changes: With line_type="with_steps" you can render a series of discrete state data (regimes, flags, tiers) as a clean staircase.
  • Annotating with markers and price lines: A thin line leaves room to layer event markers and level lines on top. See markers and price-lines.

Examples

A basic line chart

Pass a table plus timestamp and value column names. With tvl.data.values() (columns Timestamp and Value) the defaults already match, but they are shown here explicitly for clarity.

A single line is drawn through 90 daily points.

Customize color and width

color is a theme color or a CSS color of the line; line_width is an integer pixel width from 1 to 4 (the LWC default is 3). The LineWidth type alias formalizes that range as Literal[1, 2, 3, 4]. Bump width up when the chart is going on a big monitor; bump it down when you have many series overlaid.

color accepts a Deephaven theme color (e.g. "positive", "seafoam-800", "accent-300"), a hex code ("#1f77b4"), a named CSS color ("steelblue"), or an rgb()/rgba() string for transparency. Theme colors adapt automatically when the user switches themes; hardcoded values do not.

The line is drawn in the user’s theme “positive” color (so the same code reads cleanly in light or dark mode) and one pixel wide.

Every LineStyle value

line_style accepts five named presets that map to the LWC LineStyle enum: "solid", "dotted", "dashed", "large_dashed", and "sparse_dotted". To compare them in one image, give each variant its own vertical offset so the lines stack rather than overlap.

All five styles render on the same chart, vertically offset.

Every LineType value

line_type controls how the line is drawn between points. The three options are:

  • "simple": straight segments (the default).
  • "with_steps": horizontal segment then a vertical jump at each new point, useful for state data that hold constant between samples.
  • "curved": monotone-cubic interpolation for a smoothed look.

All three types render on the same chart, vertically offset. with_steps is the right choice for non-interpolated discrete-state data; curved is purely cosmetic.

One line per group with by

Set by to a partition column and the chart creates one line per unique value, automatically picking a distinct color for each from the user’s theme palette. New partition keys that show up at runtime (in a ticking table) cause new series to be added on the fly.

tvl.data.stocks() is a three-symbol (AAA, BBB, CCC) walk with enough independent variance per series that the three lines spread across the chart instead of stacking on top of each other.

Point markers on every data point

point_markers_visible=True draws a small dot at each (timestamp, value) sample so individual points stand out from the connecting line. point_markers_radius (in pixels) sizes them. Useful when the sample rate is low enough that the points themselves carry information, not just the line through them.

Each daily sample is now marked with a small filled circle on top of the line.

Pulse the last point with last_price_animation

last_price_animation controls the pulse effect on the last-price marker. "disabled" (the default) leaves it static, "continuous" pulses while the chart is visible, and "on_data_update" pulses only when new data arrives. Reach for it on live tickers where the most recent point should draw the eye.

The last-price marker now pulses continuously. Use "disabled" whenever snapshot determinism matters. The other two modes introduce time-dependent rendering.

Crosshair marker and line visibility

When the user hovers, LWC draws a marker where the crosshair meets the line. Pass crosshair_marker=tvl.crosshair_marker(...) (returns a CrosshairMarker) to style it: visible toggles it, radius sizes it (pixels), and border_color / background_color / border_width style it. line_visible=False hides the connecting line itself, handy when you only want the point markers or the crosshair dot.

These crosshair-marker options apply to area and baseline series too.

Time-proportional axis with continuous

By default (continuous=True) the chart’s time axis is laid out proportionally: points that are far apart in time are far apart on screen, and real time holes (a market close, a halted feed, missing rows) render as open gaps. Set continuous=False to opt back into the plain ordinal layout, where every consecutive point is one equal step apart and time holes collapse.

The axis layout is chart-wide: a single series with continuous=False switches the whole chart (all panes and overlays) back to ordinal. The parameter exists on every time-axis series type — for the bar-family behavior (bin-spanning bars, candle gaps) see histogram, candlestick, and bar. Numeric-axis charts (yield_curve, options_chart, custom_numeric) are unaffected.

API Reference

The result is a single-series TvlChart that can be displayed directly OR passed to chart() to be combined with other series under shared chart styling.

Returns: TvlChart A chart wrapping a single line series (or one line per partition when by is set).

ParametersTypeDefaultDescription
tableAnyDeephaven table with the data.
timestampstrColumn name for the time axis.
valuestrColumn name for the y-axis.
colorOptional[Color]NoneLine color (CSS string).
line_widthOptional[LineWidth]NoneStroke width 1–4 px.
line_styleOptional[LineStyle]NoneDash pattern; see LineStyle.
line_typeOptional[LineType]NoneGeometry between data points; see LineType.
line_visibleOptional[bool]NoneShow the line itself (set False to render only crosshair / point markers).
point_markers_visibleOptional[bool]NoneShow point markers at every data point.
point_markers_radiusOptional[float]NonePoint marker radius in pixels.
crosshair_markerOptional[CrosshairMarker]NoneStyling for the crosshair marker dot; build with crosshair_marker().
last_price_animationOptional[LastPriceAnimationMode]NoneLast-price dot animation; see LastPriceAnimationMode.
last_value_visibleOptional[bool]NoneShow the last-value badge.
titleOptional[str]NoneTitle in the series tooltip / legend.
visibleOptional[bool]NoneSeries visibility.
price_scale_idOptional[str]NonePrice-scale ID.
price_formatOptional[PriceFormat]NonePer-series price format.
last_price_lineOptional[LastPriceLine]NoneStyling for the auto last-price horizontal rule; build with last_price_line().
base_lineOptional[BaseLine]NoneStyling for the zero/index base line; build with base_line().
price_scaleOptional[PriceScale]NoneOptions for the price scale this series binds to; build with price_scale().
color_columnOptional[str]NoneColumn name supplying per-row line color.
paneOptional[int]NonePane index.
markersOptional[list[Marker]]NoneStatic markers.
price_linesOptional[list[PriceLine]]NoneHorizontal price lines.
marker_specOptional[MarkerSpec]NoneTable-driven marker spec.
continuousboolTrueTrue (default) lays the chart's time axis out proportionally, so real time gaps render as open gaps. False opts the whole chart back to the plain ordinal layout (gaps collapse to one step).
byOptional[str]NoneColumn name to partition the table by. When set, one runtime series is created per unique value; new partition keys discovered at runtime (ticking tables) add new series automatically.
on_pressOptional[PressEventCallable]NoneServer-side callback invoked when the user presses (clicks) on the chart. Receives a TvlPressEvent dict, or no argument.
on_double_pressOptional[PressEventCallable]NoneServer-side callback invoked when the user double-presses on the chart.

Create a CrosshairMarker for a series' crosshair_marker= argument.

Returns: CrosshairMarker A crosshair-marker config for crosshair_marker=.

ParametersTypeDefaultDescription
visiblebool |
None
NoneShow the crosshair marker dot.
radiusfloat |
None
NoneMarker radius in pixels.
border_colorLiteral['gray-50', 'gray-75', 'gray-100', 'gray-200', 'gray-300', 'gray-400', 'gray-500', 'gray-600', 'gray-700', 'gray-800', 'gray-900', 'red-100', 'red-200', 'red-300', 'red-400', 'red-500', 'red-600', 'red-700', 'red-800', 'red-900', 'red-1000', 'red-1100', 'red-1200', 'red-1300', 'red-1400', 'orange-100', 'orange-200', 'orange-300', 'orange-400', 'orange-500', 'orange-600', 'orange-700', 'orange-800', 'orange-900', 'orange-1000', 'orange-1100', 'orange-1200', 'orange-1300', 'orange-1400', 'yellow-100', 'yellow-200', 'yellow-300', 'yellow-400', 'yellow-500', 'yellow-600', 'yellow-700', 'yellow-800', 'yellow-900', 'yellow-1000', 'yellow-1100', 'yellow-1200', 'yellow-1300', 'yellow-1400', 'chartreuse-100', 'chartreuse-200', 'chartreuse-300', 'chartreuse-400', 'chartreuse-500', 'chartreuse-600', 'chartreuse-700', 'chartreuse-800', 'chartreuse-900', 'chartreuse-1000', 'chartreuse-1100', 'chartreuse-1200', 'chartreuse-1300', 'chartreuse-1400', 'celery-100', 'celery-200', 'celery-300', 'celery-400', 'celery-500', 'celery-600', 'celery-700', 'celery-800', 'celery-900', 'celery-1000', 'celery-1100', 'celery-1200', 'celery-1300', 'celery-1400', 'green-100', 'green-200', 'green-300', 'green-400', 'green-500', 'green-600', 'green-700', 'green-800', 'green-900', 'green-1000', 'green-1100', 'green-1200', 'green-1300', 'green-1400', 'seafoam-100', 'seafoam-200', 'seafoam-300', 'seafoam-400', 'seafoam-500', 'seafoam-600', 'seafoam-700', 'seafoam-800', 'seafoam-900', 'seafoam-1000', 'seafoam-1100', 'seafoam-1200', 'seafoam-1300', 'seafoam-1400', 'cyan-100', 'cyan-200', 'cyan-300', 'cyan-400', 'cyan-500', 'cyan-600', 'cyan-700', 'cyan-800', 'cyan-900', 'cyan-1000', 'cyan-1100', 'cyan-1200', 'cyan-1300', 'cyan-1400', 'blue-100', 'blue-200', 'blue-300', 'blue-400', 'blue-500', 'blue-600', 'blue-700', 'blue-800', 'blue-900', 'blue-1000', 'blue-1100', 'blue-1200', 'blue-1300', 'blue-1400', 'indigo-100', 'indigo-200', 'indigo-300', 'indigo-400', 'indigo-500', 'indigo-600', 'indigo-700', 'indigo-800', 'indigo-900', 'indigo-1000', 'indigo-1100', 'indigo-1200', 'indigo-1300', 'indigo-1400', 'purple-100', 'purple-200', 'purple-300', 'purple-400', 'purple-500', 'purple-600', 'purple-700', 'purple-800', 'purple-900', 'purple-1000', 'purple-1100', 'purple-1200', 'purple-1300', 'purple-1400', 'fuchsia-100', 'fuchsia-200', 'fuchsia-300', 'fuchsia-400', 'fuchsia-500', 'fuchsia-600', 'fuchsia-700', 'fuchsia-800', 'fuchsia-900', 'fuchsia-1000', 'fuchsia-1100', 'fuchsia-1200', 'fuchsia-1300', 'fuchsia-1400', 'magenta-100', 'magenta-200', 'magenta-300', 'magenta-400', 'magenta-500', 'magenta-600', 'magenta-700', 'magenta-800', 'magenta-900', 'magenta-1000', 'magenta-1100', 'magenta-1200', 'magenta-1300', 'magenta-1400', 'negative', 'notice', 'positive', 'info', 'accent', 'accent-100', 'accent-200', 'accent-300', 'accent-400', 'accent-500', 'accent-600', 'accent-700', 'accent-800', 'accent-900', 'accent-1000', 'accent-1100', 'accent-1200', 'accent-1300', 'accent-1400', 'bg', 'content-bg', 'subdued-content-bg', 'surface-bg', 'fg'] |
str |
None
NoneMarker border color.
background_colorLiteral['gray-50', 'gray-75', 'gray-100', 'gray-200', 'gray-300', 'gray-400', 'gray-500', 'gray-600', 'gray-700', 'gray-800', 'gray-900', 'red-100', 'red-200', 'red-300', 'red-400', 'red-500', 'red-600', 'red-700', 'red-800', 'red-900', 'red-1000', 'red-1100', 'red-1200', 'red-1300', 'red-1400', 'orange-100', 'orange-200', 'orange-300', 'orange-400', 'orange-500', 'orange-600', 'orange-700', 'orange-800', 'orange-900', 'orange-1000', 'orange-1100', 'orange-1200', 'orange-1300', 'orange-1400', 'yellow-100', 'yellow-200', 'yellow-300', 'yellow-400', 'yellow-500', 'yellow-600', 'yellow-700', 'yellow-800', 'yellow-900', 'yellow-1000', 'yellow-1100', 'yellow-1200', 'yellow-1300', 'yellow-1400', 'chartreuse-100', 'chartreuse-200', 'chartreuse-300', 'chartreuse-400', 'chartreuse-500', 'chartreuse-600', 'chartreuse-700', 'chartreuse-800', 'chartreuse-900', 'chartreuse-1000', 'chartreuse-1100', 'chartreuse-1200', 'chartreuse-1300', 'chartreuse-1400', 'celery-100', 'celery-200', 'celery-300', 'celery-400', 'celery-500', 'celery-600', 'celery-700', 'celery-800', 'celery-900', 'celery-1000', 'celery-1100', 'celery-1200', 'celery-1300', 'celery-1400', 'green-100', 'green-200', 'green-300', 'green-400', 'green-500', 'green-600', 'green-700', 'green-800', 'green-900', 'green-1000', 'green-1100', 'green-1200', 'green-1300', 'green-1400', 'seafoam-100', 'seafoam-200', 'seafoam-300', 'seafoam-400', 'seafoam-500', 'seafoam-600', 'seafoam-700', 'seafoam-800', 'seafoam-900', 'seafoam-1000', 'seafoam-1100', 'seafoam-1200', 'seafoam-1300', 'seafoam-1400', 'cyan-100', 'cyan-200', 'cyan-300', 'cyan-400', 'cyan-500', 'cyan-600', 'cyan-700', 'cyan-800', 'cyan-900', 'cyan-1000', 'cyan-1100', 'cyan-1200', 'cyan-1300', 'cyan-1400', 'blue-100', 'blue-200', 'blue-300', 'blue-400', 'blue-500', 'blue-600', 'blue-700', 'blue-800', 'blue-900', 'blue-1000', 'blue-1100', 'blue-1200', 'blue-1300', 'blue-1400', 'indigo-100', 'indigo-200', 'indigo-300', 'indigo-400', 'indigo-500', 'indigo-600', 'indigo-700', 'indigo-800', 'indigo-900', 'indigo-1000', 'indigo-1100', 'indigo-1200', 'indigo-1300', 'indigo-1400', 'purple-100', 'purple-200', 'purple-300', 'purple-400', 'purple-500', 'purple-600', 'purple-700', 'purple-800', 'purple-900', 'purple-1000', 'purple-1100', 'purple-1200', 'purple-1300', 'purple-1400', 'fuchsia-100', 'fuchsia-200', 'fuchsia-300', 'fuchsia-400', 'fuchsia-500', 'fuchsia-600', 'fuchsia-700', 'fuchsia-800', 'fuchsia-900', 'fuchsia-1000', 'fuchsia-1100', 'fuchsia-1200', 'fuchsia-1300', 'fuchsia-1400', 'magenta-100', 'magenta-200', 'magenta-300', 'magenta-400', 'magenta-500', 'magenta-600', 'magenta-700', 'magenta-800', 'magenta-900', 'magenta-1000', 'magenta-1100', 'magenta-1200', 'magenta-1300', 'magenta-1400', 'negative', 'notice', 'positive', 'info', 'accent', 'accent-100', 'accent-200', 'accent-300', 'accent-400', 'accent-500', 'accent-600', 'accent-700', 'accent-800', 'accent-900', 'accent-1000', 'accent-1100', 'accent-1200', 'accent-1300', 'accent-1400', 'bg', 'content-bg', 'subdued-content-bg', 'surface-bg', 'fg'] |
str |
None
NoneMarker fill color.
border_widthfloat |
None
NoneMarker border width in pixels.