{"record":{"id":"98b0b92f0b7590f6","repo":"apache/echarts","slug":"heatmap-must-use-with-visualmap","errorCode":null,"errorMessage":"Heatmap must use with visualMap","messagePattern":"Heatmap must use with visualMap","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/chart/heatmap/HeatmapView.ts","lineNumber":114,"sourceCode":"    readonly type = HeatmapView.type;\n\n    private _hmLayer: HeatmapLayer;\n\n    private _progressiveEls: Element[];\n\n    render(seriesModel: HeatmapSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) {\n        let visualMapOfThisSeries;\n        ecModel.eachComponent('visualMap', function (visualMap: VisualMapModel) {\n            visualMap.eachTargetSeries(function (targetSeries) {\n                if (targetSeries === seriesModel) {\n                    visualMapOfThisSeries = visualMap;\n                }\n            });\n        });\n\n        if (__DEV__) {\n            if (!visualMapOfThisSeries) {\n                throw new Error('Heatmap must use with visualMap');\n            }\n        }\n\n        // Clear previously rendered progressive elements.\n        this._progressiveEls = null;\n\n        this.group.removeAll();\n\n        const coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type === 'cartesian2d'\n            || coordSys.type === 'calendar'\n            || coordSys.type === 'matrix'\n        ) {\n            this._renderOnGridLike(seriesModel, api, 0, seriesModel.getData().count());\n        }\n        else if (isGeoLikeCoordSys(coordSys)) {\n            this._renderOnGeo(\n                coordSys, seriesModel, visualMapOfThisSeries, api","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/apache/echarts/blob/30076aedcd7b7f65d8dd8e8d9ece46ce778133a3/src/chart/heatmap/HeatmapView.ts#L96-L132","documentation":"DEV-only guard in HeatmapView.render: a heatmap series encodes value->color exclusively through a visualMap component. The render walks ecModel's visualMap components and checks whether any targets this series; if none does, it throws. Without a visualMap the heatmap has no color mapping, so dev builds refuse to render. Stripped in production (cells would render without color encoding).","triggerScenarios":"Declaring a series of type 'heatmap' with no visualMap component in the option, or with a visualMap whose target series index/id does not include this heatmap.","commonSituations":"Removing visualMap while debugging; copying a heatmap snippet but dropping the visualMap block; seriesIndex/seriesId mismatch on the visualMap.","solutions":["Add a visualMap component (continuous or piecewise) whose range covers the heatmap data values","Ensure the visualMap targets the heatmap (by default it targets all series; otherwise set seriesIndex)","If a single fill color suffices, consider a different chart type (e.g. bar)"],"exampleFix":"// before\nchart.setOption({ series: [{ type: 'heatmap', data: [...] }] });\n\n// after\nchart.setOption({\n  tooltip: {},\n  visualMap: { min: 0, max: 10, calculable: true, orient: 'horizontal' },\n  series: [{ type: 'heatmap', data: [...] }]\n});","handlingStrategy":"validation","validationCode":"const series = option.series || [];\nconst hasHeatmap = series.some((s: any) => s.type === 'heatmap');\nconst hasVisualMap = !!option.visualMap;\nif (hasHeatmap && !hasVisualMap) {\n  console.error('[heatmap] a visualMap component is required');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair a heatmap with a visualMap","Validate option shape before setOption","Cross-check visualMap.seriesIndex targets the heatmap"],"tags":["heatmap","visualmap","configuration","dev-only"],"backgroundTag":null,"analyzedSha":"30076aedcd7b7f65d8dd8e8d9ece46ce778133a3","analyzedAt":"2026-08-12T12:42:28.134Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}