From 8968a86da2a47883dd2b7fdf08472a1579c7bfcb Mon Sep 17 00:00:00 2001 From: Xavier Fernandes Date: Mon, 24 May 2021 13:15:47 -0700 Subject: [PATCH 1/2] Add a per result bar chart summarizing the Perspective scores Bump postcss based on Dependabot alert --- frontend/app.css | 9 ++ .../components/PerspectiveScoresBarChart.tsx | 112 ++++++++++++++++++ frontend/components/TextGenerationResults.tsx | 23 +++- package.json | 1 + transformerviz/server.py | 5 +- 5 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 frontend/components/PerspectiveScoresBarChart.tsx diff --git a/frontend/app.css b/frontend/app.css index 5afc150..5390aae 100644 --- a/frontend/app.css +++ b/frontend/app.css @@ -45,3 +45,12 @@ body { flex-grow: 1; font-style: bold; } + +.bar { + fill: rgba(252, 84, 104, 1); +} + +.highlighted-bar { + stroke-width: 2px; + stroke: rgb(0,0,0, 1); +} diff --git a/frontend/components/PerspectiveScoresBarChart.tsx b/frontend/components/PerspectiveScoresBarChart.tsx new file mode 100644 index 0000000..27e5fc1 --- /dev/null +++ b/frontend/components/PerspectiveScoresBarChart.tsx @@ -0,0 +1,112 @@ +import React, { Component } from "react"; +import ReactDOM from "react-dom"; +import * as d3 from "d3"; +import { DirectionalHint } from 'office-ui-fabric-react/lib/Tooltip'; +import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button'; + + +type PerspectiveScoresBarChartState = { + selectedScore: string +} + +type PerspectiveScoresBarChartProps = { + id: number, + scores: any, + defaultSelectedScore: string +} + +class PerspectiveScoresBarChart extends Component { + + constructor(props) { + super(props); + + this.state = { + selectedScore: props.defaultSelectedScore + }; + + this.node = React.createRef(); + this.domID = `perspectivescoresbarchart-${props.id}`; + } + + node: React.RefObject + + domID: string + + componentDidMount() { + this.createDistributionBarChart(); + } + + componentDidUpdate() { + this.createDistributionBarChart(); + } + + setSelectedScore = (selectedScore: string) => { + this.setState({ + selectedScore: selectedScore + }); + } + + createDistributionBarChart = () => { + var _this = this; + var body = d3.select(this.node.current); + + var margin = { top: 5, right: 15, bottom: 50, left: 55 } + var h = 111 - margin.top - margin.bottom + var w = 200; + + // SVG + d3.select(`#${this.domID}`).remove(); + var svg = body.append('svg') + .attr('id', this.domID) + .attr('height',h + margin.top + margin.bottom) + .attr('width',w) + .attr('float', 'left'); + + var xScale = d3.scaleBand().range([0, w]).padding(0.4), + yScale = d3.scaleLinear().range([h, 0]); + + var g = svg.append("g") + .attr("transform", "translate(" + 55 + "," + margin.top + ")"); + + xScale.domain(this.props.scores.map(function(d) { return d.score; })); + yScale.domain([0.0, 1.0]); + + var selectedScoreObj = this.props.scores.filter(scoreObj => (scoreObj.score == this.state.selectedScore))[0]; + var selectedScoreMessage = `${selectedScoreObj.scoreName}: ${selectedScoreObj.value.toFixed(2)}`; + + g.append("g") + .attr("transform", "translate(0," + h + ")") + .append("text") + .attr("y", 30) + .attr("x", (w + margin.left)/2) + .attr("text-anchor", "end") + .attr("fill", "black") + .attr("font-size", "14px") + .text(selectedScoreMessage); + + g.selectAll(".bar") + .data(this.props.scores) + .enter().append("rect") + .attr("class", "bar") + .attr("x", function(d) { return xScale(d.score); }) + .attr("y", function(d) { return yScale(d.value); }) + .attr("width", xScale.bandwidth()) + .attr("height", function(d) { return h - yScale(d.value); }) + .classed("highlighted-bar", function(d) { return d.score == _this.state.selectedScore }) + .on("click", function(d) { + _this.setSelectedScore(d.score); + }); + } + + render() { + return ( +
+
+
+ ); + } +} + + + +export default PerspectiveScoresBarChart; diff --git a/frontend/components/TextGenerationResults.tsx b/frontend/components/TextGenerationResults.tsx index 246d90d..8af9d8a 100644 --- a/frontend/components/TextGenerationResults.tsx +++ b/frontend/components/TextGenerationResults.tsx @@ -1,6 +1,12 @@ import React from "react"; import * as _ from "lodash" import AnalyzedText from "../models/AnalyzedText"; +import ReactDOM from "react-dom"; +import { Fabric } from "office-ui-fabric-react/lib/Fabric"; +import { TextField } from "office-ui-fabric-react/lib/TextField"; +import { DefaultButton } from "office-ui-fabric-react/lib/Button"; +import { List } from "office-ui-fabric-react/lib/List"; +import PerspectiveScoresBarChart from "./PerspectiveScoresBarChart"; type TextGenerationResultsProps = { analysisResults: AnalyzedText[], @@ -33,6 +39,21 @@ class TextGenerationResults extends React.Component { + let resultScores = [ + {score: "TOXICITY", value: item.toxicity, scoreName: "Toxicity"}, + {score: "SEVERE_TOXICITY", value: item.severeToxicity, scoreName: "Severe Toxicity"}, + {score: "IDENTITY_ATTACK", value: item.identityAttack, scoreName: "Identity Attack"}, + {score: "INSULT", value: item.insult, scoreName: "Insult"}, + {score: "PROFANITY", value: item.profanity, scoreName: "Profanity"}, + {score: "THREAT", value: item.threat, scoreName: "Threat"}, + {score: "SEXUALLY_EXPLICIT", value: item.sexuallyExplicit, scoreName: "Sexually Explicit"}, + {score: "FLIRTATION", value: item.flirtation, scoreName: "Flirtation"} + ]; + + return resultScores; + } + return (

Generated Results

@@ -42,7 +63,7 @@ class TextGenerationResults extends React.Component
- BAR CHART HERE +