View table code
{
  const data = data_extendedTable2_total;
  const colorFill = "#216729";
  const langLook = {
    obs: Lang.toSentenceCase(
      _lang(nbText.supportNbText.words.observation.plural)
    )
  };
  const y = (d) => _lang(td.Practice.values?.[d]);

  return Plot.plot({
    width: 900,
    height: 700,
    marginLeft: 190,
    marginRight: 50,
    marginTop: 60,
    x: {
      tickFormat: "s",
      axis: "top",
      label: langLook.obs,
      labelOffset: 40,
      labelAnchor: "center",
      labelArrow: "none",
      grid: true
    },
    y: {
      label: null
    },
    marks: [
      Plot.ruleX([0]),
      Plot.barX(data, {
        x: "observations",
        y: (d) => y(d.practice),
        sort: { y: "x", reverse: true },
        fill: colorFill
      }),
      Plot.textX(
        data,
        Plot.map(
          { text: (v) => v.map((d) => `${d3.format(".2s")(d)} obs.`) },
          {
            x: "observations",
            y: (d) => y(d.practice),
            text: "observations",
            textAnchor: "start",
            dx: 5,
            fill: "#333"
          }
        )
      )
    ]
  });
}

View table code
{
  const plotData = data_meanDiff_practiceCrop_new.filter(
    (d) => d.Crop === selectCropMeanDiff_new.field
  );
  const marginBottom = 0;
  const marginTop = 60;
  const yHeight = 25;
  const height =
    marginTop +
    marginBottom +
    d3.group(plotData, (d) => d.Practice).size * yHeight;
  const _formatNum = formatNum;
  const _toggleCIs = toggleCIsCrop_new;
  const _radioSort = radioSortDotPlotCrop_new;
  const langLookup = {
    xLabel: _lang(nbText.practicalImpact.labels.xMeanDiff),
    tooltip: {
      aez: _lang(nbText.practicalImpact.tooltips.aez),
      meanDiff: _lang(nbText.practicalImpact.tooltips.meanDiff),
      meanControl: _lang(nbText.practicalImpact.tooltips.meanControl),
      crop: Lang.toSentenceCase(_lang(nbText.supportNbText.words.crop.singular)),
      ciLo: _lang(nbText.practicalImpact.tooltips.ciLower),
      ciHi: _lang(nbText.practicalImpact.tooltips.ciUpper),
      obs: Lang.toSentenceCase(_lang(nbText.supportNbText.words.observation.plural)),
      practice: Lang.toSentenceCase(_lang(nbText.supportNbText.words.practice.singular))
    }
  }
  const y = (d) => _lang(td.Practice.values?.[d]);

  return Plot.plot({
    height,
    marginBottom,
    marginTop,
    marginLeft: 200,
    marginRight: 70,
    width: 900,
    x: {
      axis: "top",
      nice: true,
      grid: true,
      label: langLookup.xLabel,
      labelAnchor: "center",
      labelOffset: 40,
      labelArrow: "none"
    },
    y: {
      tickSize: 0,
      label: null
    },
    color: {
      range: colorYellowGreen
    },
    marks: [
      // main y-axis
      Plot.axisY({
        tickSize: 0
      }),
      // pointer white-out
      Plot.axisY(
        Plot.pointerY({
          fill: "white",
          textStroke: "white",
          textStrokeWidth: 2,
          tickSize: 0
        })
      ),
      // bold pointer
      Plot.axisY(
        Plot.pointerY({
          fontWeight: "bold",
          tickSize: 0
        })
      ),
      // zero point
      Plot.ruleX([0], { stroke: "#333", strokeDasharray: [4] }),
      // span lines: CI
      Plot.ruleY(_toggleCIs.length > 0 ? plotData : [], {
        y: (d) => y(d.Practice),
        x1: (d) => d.Lower,
        x2: (d) => d.Upper,
        stroke: "#333"
      }),
      // mean diff dots
      Plot.dot(plotData, {
        x: "Mean_Difference",
        y: (d) => y(d.Practice),
        sort: { y: _radioSort.channel, reverse: _radioSort.reverse },
        fill: (d) => d.Mean_Difference,
        r: 8,
        stroke: "#fff",
        strokeWidth: 0.7,
        channels: {
          nObs: {
            value: "N_Obs"
          },
          prac: {
            value: (d) => y(d.Practice),
          },
          crop: {
            value: "Crop"
          },
          diff: {
            label: langLookup.tooltip.meanDiff,
            value: "Mean_Difference"
          },
          control: {
            label: langLookup.tooltip.meanControl,
            value: 'Mean_Control',
          },
          ciLow: {
            label: langLookup.tooltip.ciLo,
            value: "Lower"
          },
          ciHigh: {
            label: langLookup.tooltip.ciHi,
            value: "Upper"
          }
        },
        tip: {
          format: {
            x: false,
            y: false,
            fill: false,
            prac: false,
            crop: false,
            nObs: false,
            diff: (d) => _formatNum(d),
            control: (d) => _formatNum(d),
            ciLow: (d) => _formatNum(d),
            ciHigh: (d) => _formatNum(d)
          }
        }
      }),
      // dot highlight on hover
      Plot.dot(plotData, Plot.pointer({
        x: "Mean_Difference",
        y: (d) => y(d.Practice),
        r: 8,
        stroke: "#333",
        strokeWidth: 0.7,
        channels: {
          nObs: {
            label: "# Observations",
            value: "N_Obs"
          },
        }
      })),
      // observation counts
      Plot.textY(plotData, {
        y: (d) => y(d.Practice),
        text: (d) => d.N_Obs + " obs.",
        frameAnchor: "right",
        textAnchor: "start",
        dx: 16
      }),
      // counts white-out
      Plot.textY(
        plotData,
        Plot.pointerY({
          y: (d) => y(d.Practice),
          text: (d) => d.N_Obs + " obs.",
          fill: "white",
          stroke: "white",
          strokeWidth: 2,
          frameAnchor: "right",
          textAnchor: "start",
          dx: 16
        })
      ),
      // counts bold hover
      Plot.textY(
        plotData,
        Plot.pointerY({
          y: (d) => y(d.Practice),
          text: (d) => d.N_Obs + " obs.",
          fontWeight: "bold",
          frameAnchor: "right",
          textAnchor: "start",
          dx: 16
        })
      )
    ]
  });
}

View table code
plotDotAEZ_new = {
  const baseData = data_meanDiff_aezPracticeCrop_new;
  const plotData = baseData.filter(
    (d) => d.Crop === selectCropMeanDiffAEZ.field
  );
  const aezData = T.tidy(
    plotData,
    T.filter((d) => {
      if (aezSelect_new.field == null) return d;
      return d.AEZ_Class_FAO == aezSelect_new.field;
    }),
    T.arrange("Mean_Difference")
  );
  const colorDomain = aezColor_new.domain;
  const colorRange = aezColor_new.range;
  const marginBottom = 0;
  const marginTop = 80;
  const yHeight = 25;
  const height =
    marginTop +
    marginBottom +
    d3.group(plotData, (d) => d.Practice).size * yHeight;
  const _formatNum = formatNum;
  const _toggleCIs = toggleCIsCropAEZ_new;
  const _radioSort = radioSortDotPlotCropAEZ_new;
  const langLookup = {
    xLabel: _lang(nbText.practicalImpact.labels.xMeanDiff),
    tooltip: {
      aez: _lang(nbText.practicalImpact.tooltips.aez),
      meanDiff: _lang(nbText.practicalImpact.tooltips.meanDiff),
      meanControl: _lang(nbText.practicalImpact.tooltips.meanControl),
      crop: Lang.toSentenceCase(
        _lang(nbText.supportNbText.words.crop.singular)
      ),
      ciLo: _lang(nbText.practicalImpact.tooltips.ciLower),
      ciHi: _lang(nbText.practicalImpact.tooltips.ciUpper),
      obs: Lang.toSentenceCase(
        _lang(nbText.supportNbText.words.observation.plural)
      ),
      practice: Lang.toSentenceCase(
        _lang(nbText.supportNbText.words.practice.singular)
      )
    }
  };
  const y = (d) => _lang(td.Practice.values?.[d]);
  const color = (d) => _lang(td.AEZ_Class_FAO.values?.[d]);

  return Plot.plot({
    height,
    marginBottom,
    marginTop,
    marginLeft: 200,
    marginRight: 70,
    width: 900,
    x: {
      axis: "top",
      nice: true,
      grid: true,
      label: langLookup.xLabel,
      labelAnchor: "center",
      labelOffset: 40,
      labelArrow: "none"
    },
    y: {
      tickSize: 0,
      label: null
    },
    color: {
      domain: colorDomain,
      range: colorRange
    },
    marks: [
      // main y-axis
      Plot.axisY({
        tickSize: 0
      }),
      // pointer white-out
      Plot.axisY(
        Plot.pointerY({
          fill: "white",
          textStroke: "white",
          textStrokeWidth: 2,
          tickSize: 0
        })
      ),
      // bold pointer
      Plot.axisY(
        Plot.pointerY({
          fontWeight: "bold",
          tickSize: 0
        })
      ),
      // zero point
      Plot.ruleX([0], { stroke: "#333", strokeDasharray: [4] }),
      // base dots
      Plot.dot(plotData, {
        x: "Mean_Difference",
        y: (d) => y(d.Practice),
        sort: { y: _radioSort.channel, reverse: _radioSort.reverse },
        r: 8,
        stroke: "#fff",
        strokeWidth: 0.7,
        fill: "#efefef",
        channels: {
          nObs: {
            label: "# Observations",
            value: "N_Obs"
          }
        }
      }),
      // selection: span lines: CI
      Plot.ruleY(_toggleCIs.length > 0 ? aezData : [], {
        y: (d) => y(d.Practice),
        x1: (d) => (d.Lower == "NA" ? null : d.Lower),
        x2: (d) => (d.Upper == "NA" ? null : d.Upper),
        stroke: "#333"
      }),
      // selection: mean diff dots
      Plot.dot(aezData, {
        x: "Mean_Difference",
        y: (d) => y(d.Practice),
        fill: (d) => {
          return color(d.AEZ_Class_FAO);
        },
        r: 8,
        stroke: "#fff",
        strokeWidth: 0.7,
        channels: {
          aez: {
            label: langLookup.tooltip.aez,
            value: (d) => color(d.AEZ_Class_FAO)
          },
          nObs: {
            label: langLookup.tooltip.obs,
            value: "N_Obs"
          },
          diff: {
            label: langLookup.tooltip.meanDiff,
            value: "Mean_Difference"
          },
          control: {
            label: langLookup.tooltip.meanControl,
            value: "Mean_Control"
          },
          prac: {
            label: langLookup.tooltip.practice,
            value: (d) => y(d.Practice)
          },
          crop: {
            label: langLookup.tooltip.crop,
            value: "Crop"
          },
          ciLow: {
            label: langLookup.tooltip.ciLo,
            value: "Lower"
          },
          ciHigh: {
            label: langLookup.tooltip.ciHi,
            value: "Upper"
          }
        },
        tip: {
          format: {
            x: false,
            y: false,
            fill: false,
            prac: false,
            crop: false,
            aez: true,
            diff: (d) => _formatNum(d),
            control: (d) => _formatNum(d),
            ciLow: (d) => _formatNum(d),
            ciHigh: (d) => _formatNum(d),
            nObs: true
          }
        }
      }),
      // dot highlight on hover
      Plot.dot(
        aezData,
        Plot.pointer({
          x: "Mean_Difference",
          y: (d) => y(d.Practice),
          r: 8,
          fill: (d) => {
            return d.AEZ_Class_FAO;
          },
          stroke: "#333",
          strokeWidth: 0.7,
          channels: {
            nObs: {
              label: "# Observations",
              value: "N_Obs"
            }
          }
        })
      ),
      // observation counts
      Plot.textY(
        aezData,
        Plot.map(
          { text: (values) => values.map((d) => d + " obs.") },
          Plot.groupY(
            { text: "sum" },
            {
              y: (d) => y(d.Practice),
              text: "N_Obs",
              frameAnchor: "right",
              textAnchor: "start",
              dx: 16
            }
          )
        )
      ),
      // digital white-out
      Plot.textY(
        aezData,
        Plot.pointerY(
          Plot.map(
            { text: (values) => values.map((d) => d + " obs.") },
            Plot.groupY(
              { text: "sum" },
              {
                y: (d) => y(d.Practice),
                text: "N_Obs",
                frameAnchor: "right",
                textAnchor: "start",
                dx: 16,
                fill: "white",
                stroke: "white",
                strokeWidth: 2
              }
            )
          )
        )
      ),
      // observation counts bold hover
      Plot.textY(
        aezData,
        Plot.pointerY(
          Plot.map(
            { text: (values) => values.map((d) => d + " obs.") },
            Plot.groupY(
              { text: "sum" },
              {
                y: (d) => y(d.Practice),
                text: "N_Obs",
                frameAnchor: "right",
                textAnchor: "start",
                dx: 16,
                fontWeight: "bold"
              }
            )
          )
        )
      )
    ]
  });
}

plotDotAEZ_new.legend('color', {columns: 3})

View table code
plotRiskBeeswarm = {
  const data = data_lclRisk;
  const langLook = {
    caption: _lang(nbText.risks.plot.caption),
    xLabel: _lang(nbText.risks.plot.xLabel),
    tooltip: {
      practice: Lang.toSentenceCase(
        _lang(nbText.supportNbText.words.practice.singular)
      ),
      combo: Lang.toSentenceCase(
        _lang(nbText.risks.plot.tooltip.inCombination)
      ),
      crop: Lang.toSentenceCase(
        _lang(nbText.supportNbText.words.crop.singular)
      ),
      obs: Lang.toSentenceCase(
        _lang(nbText.supportNbText.words.observation.plural)
      )
    }
  };
  const _practice = selectPractice.field;

  const plot = Plot.plot({
    caption: langLook.caption,
    height: 400,
    width: 800,
    marginTop: 60,
    x: {
      axis: "top",
      grid: true,
      domain: [0, 1],
      label: langLook.xLabel,
      labelOffset: 40,
      labelAnchor: "center",
      labelArrow: "none"
    },
    color: {
      domain: [0, 1],
      range: colorYellowGreen,
      legend: false,
      unknown: "#efefef"
    },
    r: {
      range: [2, 30]
    },
    marks: [
      Plot.dot(
        data,
        Plot.dodgeY(
          { anchor: "middle" },
          {
            x: "value",
            r: "observations",
            fill: (d) => {
              if (_practice === null) return d.value; // show all practices
              // show highlighted practice only
              return d.practice === _practice ? d.value : null;
            },
            stroke: "#fff",
            strokeWidth: 1,
            channels: {
              practice: {
                label: langLook.tooltip.practice,
                value: (d) => _lang(td.Practice.values[d.practice])
              },
              product: {
                label: langLook.tooltip.crop,
                value: (d) => d.product
              },
              nObs: {
                label: langLook.tooltip.obs,
                value: (d) => d.observations
              },
              combo: {
                label: langLook.tooltip.combo,
                value: (d) =>
                  d.is_combo
                    ? Lang.toTitleCase(_lang(nbText.supportNbText.bools.yes))
                    : Lang.toTitleCase(_lang(nbText.supportNbText.bools.no))
              }
            },
            tip: {
              px: (d) => {
                if (_practice === null) return d.value; // show all practices
                // show highlighted practice only
                return d.practice === _practice ? d.value : null;
              },
              maxRadius: 6,
              format: {
                x: false,
                y: false,
                fill: false,
                r: false,
                practice: true,
                combo: true,
                product: true,
                px: (d) => formatNum(d),
                nObs: true
              }
            }
          }
        )
      )
    ]
  });

  return plot;
}

View table code
{
  const plotData = dataAdoptionFactorsMap.get(dataAdoptionFactors_select.field);
  const _fillLookup = adoptionFactorsLookup;
  const _sorter = radioSortAdoptionFactors;
  const colorOrder = [
    _fillLookup["Negative"],
    _fillLookup["Not significant"],
    _fillLookup["Positive"]
  ];
  const colorRange = ["#EC5A47", "#F4BB21", "#216729"];
  const y = (d) => _lang(td.adoption_factors.values?.[d]);

  return Plot.plot({
    width: 1000,
    height: 400,
    marginLeft: 180,
    marginRight: 50,
    x: {
      axis: null
      // label: "% Total"
      // labelOffset: 40,
      // labelAnchor: "center"
    },
    y: {
      label: null,
      tickSize: 0,
      padding: 0
    },
    color: {
      domain: colorOrder,
      range: colorRange,
      legend: true
    },
    marks: [
      // main y-axis
      Plot.axisY({
        tickSize: 0
      }),
      // pointer white-out
      Plot.axisY(
        Plot.pointerY({
          fill: "white",
          textStroke: "white",
          textStrokeWidth: 2,
          tickSize: 0
        })
      ),
      // bold pointer
      Plot.axisY(
        Plot.pointerY({
          fontWeight: "bold",
          tickSize: 0
        })
      ),
      // bars
      Plot.barX(
        plotData,
        Plot.stackX({
          x: "perc",
          y: (d) => y(d.factor),
          sort: { y: _sorter.channel, reverse: _sorter.reverse },
          fill: (d) => _fillLookup[d.direction],
          order: colorOrder,
          stroke: "#fff",
          channels: {
            percentage: {
              label: Lang.toSentenceCase(
                _lang(nbText.supportNbText.words.percentage.singular)
              ),
              value: "perc"
            },
            total: "total",
            n: {
              label: Lang.toSentenceCase(
                _lang(nbText.supportNbText.words.observation.plural)
              ),
              value: "n"
            }
          },
          tip: {
            format: {
              x: false,
              y: false,
              fill: false,
              total: false,
              percentage: (d) => `${d3.format("d")(d)}%`,
              n: true
            }
          }
        })
      ),
      markBoldSidebarText(plotData, {
        y: (d) => y(d.factor),
        text: "n",
        dx: 7
      })
    ]
  });
}