Engineering Stress-Strain Curve — Apache ECharts

An engineering stress-strain curve visualizes the relationship between applied stress (MPa) and resulting strain (dimensionless) in a material under uniaxial tensile loading. The curve reveals distinct mechanical behavior regions — elastic deformation, yielding, strain hardening, and necking — culminating in fracture. It is the foundational plot for characterizing material mechanical properties and comparing material performance.

Engineering Stress-Strain Curve rendered with Apache ECharts

Renders

JavaScript source (Apache ECharts)

// anyplot.ai
// line-stress-strain: Engineering Stress-Strain Curve
// Library: echarts 6.1.0 | JavaScript 22.23.2
// Quality: 91/100 | Created: 2026-08-24

const t = window.ANYPLOT_TOKENS;

// --- Deterministic noise (small-amplitude, fixed-seed LCG) ------------------
function lcg(seed) {
  let state = seed >>> 0;
  return function () {
    state = (1664525 * state + 1013904223) >>> 0;
    return state / 4294967296;
  };
}
const rand = lcg(42);

// --- Piecewise stress-strain curve builder -----------------------------------
// `knots` are [strain, stress] control points; `segments[i]` describes the leg
// between knots[i] and knots[i+1]: point count, whether to ease the stress
// interpolation (smoothstep, for a rounded knee/plateau/necking shape) or keep
// it linear (Hooke's law elastic region), and noise amplitude in MPa.
function buildCurve(knots, segments) {
  const strain = [];
  const stress = [];
  for (let s = 0; s < segments.length; s++) {
    const [x0, y0] = knots[s];
    const [x1, y1] = knots[s + 1];
    const { n, eased, noise } = segments[s];
    const start = s === 0 ? 0 : 1;
    for (let i = start; i <= n; i++) {
      const tt = i / n;
      const et = eased ? tt * tt * (3 - 2 * tt) : tt;
      const strainVal = x0 + (x1 - x0) * tt;
      let stressVal = y0 + (y1 - y0) * et;
      if (noise) stressVal += (rand() - 0.5) * noise;
      strain.push(Number(strainVal.toFixed(5)));
      stress.push(Number(stressVal.toFixed(1)));
    }
  }
  return strain.map((s, i) => [s, stress[i]]);
}

// --- Mild steel: sharp yield point + Luders plateau + hardening + necking ---
const STEEL_E = 200000; // MPa (Young's modulus, ~200 GPa)
const STEEL_YIELD_STRAIN = 0.00125;
const STEEL_YIELD_STRESS = STEEL_E * STEEL_YIELD_STRAIN; // 250 MPa
const STEEL_UTS_STRAIN = 0.2;
const STEEL_UTS_STRESS = 400;
const STEEL_FRACTURE_STRAIN = 0.27;
const STEEL_FRACTURE_STRESS = 322;

const steelCurve = buildCurve(
  [
    [0, 0],
    [STEEL_YIELD_STRAIN, STEEL_YIELD_STRESS],
    [0.02, 251],
    [STEEL_UTS_STRAIN, STEEL_UTS_STRESS],
    [STEEL_FRACTURE_STRAIN, STEEL_FRACTURE_STRESS],
  ],
  [
    { n: 20, eased: false, noise: 0 }, // elastic (Hooke's law, no noise)
    { n: 25, eased: false, noise: 2.5 }, // Luders plateau (serrated yielding)
    { n: 90, eased: true, noise: 2.5 }, // strain hardening
    { n: 45, eased: true, noise: 2 }, // necking to fracture
  ],
);

// --- Aluminum alloy: gradual rounded knee, lower ductility, comparison series
const AL_E = 70000; // MPa (Young's modulus, ~70 GPa)
const AL_KNEE_STRAIN = 0.0038;
const AL_KNEE_STRESS = AL_E * AL_KNEE_STRAIN;
const AL_UTS_STRAIN = 0.1;
const AL_UTS_STRESS = 310;
const AL_FRACTURE_STRAIN = 0.135;
const AL_FRACTURE_STRESS = 296;

const aluminumCurve = buildCurve(
  [
    [0, 0],
    [AL_KNEE_STRAIN, AL_KNEE_STRESS],
    [AL_UTS_STRAIN, AL_UTS_STRESS],
    [AL_FRACTURE_STRAIN, AL_FRACTURE_STRESS],
  ],
  [
    { n: 15, eased: false, noise: 0 }, // elastic (Hooke's law, no noise)
    { n: 90, eased: true, noise: 1 }, // rounded knee into gradual hardening
    { n: 30, eased: true, noise: 1 }, // necking to fracture
  ],
);

// --- 0.2% offset construction line: parallel to the elastic modulus slope,
// shifted 0.002 strain — its intersection with the curve is the offset yield
// point. For steel's flat plateau, that intersection sits at ~250 MPa.
const offsetIntersectionStrain = 0.002 + STEEL_YIELD_STRESS / STEEL_E;
const offsetLineEndStrain = offsetIntersectionStrain + 0.0011;
const offsetLine = [
  [0.002, 0],
  [offsetLineEndStrain, STEEL_E * (offsetLineEndStrain - 0.002)],
];

// --- Init ---------------------------------------------------------------------
const chart = echarts.init(document.getElementById("container"));

// --- Option ---------------------------------------------------------------
chart.setOption({
  animation: false,
  color: t.palette,
  backgroundColor: "transparent",
  title: {
    text: "line-stress-strain · javascript · echarts · anyplot.ai",
    left: "center",
    top: 24,
    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },
  },
  legend: {
    data: ["Mild steel", "Aluminum alloy"],
    top: 66,
    right: 70,
    textStyle: { color: t.inkSoft, fontSize: 15 },
    itemWidth: 24,
    itemHeight: 3,
  },
  grid: { left: 120, right: 170, top: 150, bottom: 110 },
  xAxis: {
    type: "value",
    name: "Engineering Strain (mm/mm)",
    nameLocation: "middle",
    nameGap: 44,
    min: 0,
    max: 0.3,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    axisLabel: { color: t.inkSoft, fontSize: 14 },
    axisLine: { lineStyle: { color: t.inkSoft } },
    axisTick: { show: false },
    splitLine: { show: false },
  },
  yAxis: {
    type: "value",
    name: "Engineering Stress (MPa)",
    nameLocation: "middle",
    nameGap: 68,
    min: 0,
    max: 480,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    axisLabel: { color: t.inkSoft, fontSize: 14 },
    axisLine: { show: false },
    axisTick: { show: false },
    splitLine: { lineStyle: { color: t.grid } },
  },
  series: [
    {
      name: "0.2% Offset",
      type: "line",
      data: offsetLine,
      showSymbol: false,
      silent: true,
      lineStyle: { color: t.inkSoft, width: 2, type: "dashed" },
      z: 2,
    },
    {
      name: "Mild steel",
      type: "line",
      data: steelCurve,
      showSymbol: false,
      smooth: false,
      lineStyle: { color: t.palette[0], width: 3.5 },
      z: 3,
      markPoint: {
        symbolSize: 16,
        itemStyle: { color: t.ink, borderColor: t.pageBg, borderWidth: 2 },
        label: { color: t.ink, fontSize: 14, fontWeight: 500 },
        data: [
          {
            name: "Yield",
            coord: [offsetIntersectionStrain, STEEL_YIELD_STRESS],
            symbol: "circle",
            label: {
              formatter: "Yield ≈ 250 MPa\n(0.2% offset)",
              position: [28, 44],
            },
          },
          {
            name: "UTS",
            coord: [STEEL_UTS_STRAIN, STEEL_UTS_STRESS],
            symbol: "circle",
            label: {
              formatter: `UTS ≈ ${STEEL_UTS_STRESS} MPa`,
              position: "top",
              distance: 10,
            },
          },
          {
            name: "Fracture",
            coord: [STEEL_FRACTURE_STRAIN, STEEL_FRACTURE_STRESS],
            symbol: "diamond",
            symbolSize: 15,
            label: {
              formatter: "Fracture",
              position: "right",
              distance: 12,
            },
          },
          {
            name: "Modulus label",
            coord: [0.024, 340],
            symbol: "circle",
            symbolSize: 4,
            itemStyle: { color: t.pageBg, borderColor: t.pageBg },
            label: {
              show: true,
              formatter: "E ≈ 200 GPa",
              color: t.inkSoft,
              fontSize: 14,
              fontStyle: "italic",
              position: "top",
            },
          },
          {
            name: "Elastic phase",
            coord: [0.015, 445],
            symbol: "circle",
            symbolSize: 4,
            itemStyle: { color: t.pageBg, borderColor: t.pageBg },
            label: {
              show: true,
              formatter: "Elastic",
              color: t.inkSoft,
              fontSize: 15,
              fontWeight: 500,
              position: "top",
            },
          },
          {
            name: "Hardening phase",
            coord: [0.1, 445],
            symbol: "circle",
            symbolSize: 4,
            itemStyle: { color: t.pageBg, borderColor: t.pageBg },
            label: {
              show: true,
              formatter: "Strain hardening",
              color: t.inkSoft,
              fontSize: 15,
              fontWeight: 500,
              position: "top",
            },
          },
          {
            name: "Necking phase",
            coord: [0.235, 445],
            symbol: "circle",
            symbolSize: 4,
            itemStyle: { color: t.pageBg, borderColor: t.pageBg },
            label: {
              show: true,
              formatter: "Necking",
              color: t.inkSoft,
              fontSize: 15,
              fontWeight: 500,
              position: "top",
            },
          },
        ],
      },
    },
    {
      name: "Aluminum alloy",
      type: "line",
      data: aluminumCurve,
      showSymbol: false,
      smooth: false,
      lineStyle: { color: t.palette[1], width: 3 },
      z: 1,
    },
  ],
});

Part of Engineering Stress-Strain Curve on anyplot.ai.

Other implementations