| @@ -0,0 +1,35 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <svg width="24px" height="19px" viewBox="0 0 24 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |||||
| <!-- Generator: Sketch 63.1 (92452) - https://sketch.com --> | |||||
| <title>fn</title> | |||||
| <desc>Created with Sketch.</desc> | |||||
| <defs> | |||||
| <path d="M17.1480906,0.0392739336 L18.3266093,0.00728953835 C18.6341197,-0.00105613749 18.9283586,0.132596377 19.1243929,0.369667804 L20,1.42857143 L20,1.42857143 L10.4761905,1.42857143 L10.4761905,0.0392739336 L17.1480906,0.0392739336 Z" id="path-1"></path> | |||||
| <filter x="-36.8%" y="-174.5%" width="173.5%" height="589.5%" filterUnits="objectBoundingBox" id="filter-2"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| <path d="M1,0 L18.04761,0 C18.5998948,-2.12475365e-16 19.04761,0.44771525 19.04761,1 L19.04761,10.875081 C19.0475959,11.6828644 18.5616641,12.411342 17.8158526,12.721631 C14.1649895,14.2405437 11.4009752,15 9.52380952,15 C7.64664694,15 4.88263611,14.2405461 1.23177702,12.7216384 C0.485941676,12.4113657 9.8926869e-17,11.682874 0,10.8750748 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z" id="path-3"></path> | |||||
| <filter x="-18.4%" y="-16.7%" width="136.8%" height="146.7%" filterUnits="objectBoundingBox" id="filter-4"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| </defs> | |||||
| <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | |||||
| <g id="fn" transform="translate(12.000000, 8.500000) scale(-1, 1) translate(-12.000000, -8.500000) translate(2.000000, 1.000000)"> | |||||
| <g id="Rectangle-34" fill-rule="nonzero"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use> | |||||
| <use fill="#9E1C17" xlink:href="#path-1"></use> | |||||
| </g> | |||||
| <g id="Rectangle-34" fill-rule="nonzero"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use> | |||||
| <use fill="#F66F6A" xlink:href="#path-3"></use> | |||||
| </g> | |||||
| <text id="FN" transform="translate(9.500000, 7.000000) scale(-1, 1) translate(-9.500000, -7.000000) " font-family="PingFangSC-Medium, PingFang SC" font-size="8" font-weight="400" line-spacing="12" fill="#FFFFFF"> | |||||
| <tspan x="4" y="9">FN</tspan> | |||||
| </text> | |||||
| </g> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -0,0 +1,33 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <svg width="24px" height="19px" viewBox="0 0 24 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |||||
| <!-- Generator: Sketch 63.1 (92452) - https://sketch.com --> | |||||
| <title>yuce</title> | |||||
| <desc>Created with Sketch.</desc> | |||||
| <defs> | |||||
| <path d="M17.1480906,0.0392739336 L18.3266093,0.00728953835 C18.6341197,-0.00105613749 18.9283586,0.132596377 19.1243929,0.369667804 L20,1.42857143 L20,1.42857143 L10.4761905,1.42857143 L10.4761905,0.0392739336 L17.1480906,0.0392739336 Z" id="path-1"></path> | |||||
| <filter x="-36.8%" y="-174.5%" width="173.5%" height="589.5%" filterUnits="objectBoundingBox" id="filter-2"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| <path d="M1,0 L18.04761,0 C18.5998948,-2.12475365e-16 19.04761,0.44771525 19.04761,1 L19.04761,10.875081 C19.0475959,11.6828644 18.5616641,12.411342 17.8158526,12.721631 C14.1649895,14.2405437 11.4009752,15 9.52380952,15 C7.64664694,15 4.88263611,14.2405461 1.23177702,12.7216384 C0.485941676,12.4113657 9.8926869e-17,11.682874 0,10.8750748 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z" id="path-3"></path> | |||||
| <filter x="-18.4%" y="-16.7%" width="136.8%" height="146.7%" filterUnits="objectBoundingBox" id="filter-4"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| </defs> | |||||
| <g id="MindExplain" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | |||||
| <g id="yuce" transform="translate(12.000000, 8.500000) scale(-1, 1) translate(-12.000000, -8.500000) translate(2.000000, 1.000000)" fill-rule="nonzero"> | |||||
| <g id="Rectangle-34"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use> | |||||
| <use fill="#B37B00" xlink:href="#path-1"></use> | |||||
| </g> | |||||
| <g id="Rectangle-34"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use> | |||||
| <use fill="#FFAF00" xlink:href="#path-3"></use> | |||||
| </g> | |||||
| <path d="M6.28,8.52 L6.28,5.336 L8.384,5.336 L8.384,8.52 L9.096,8.52 L9.096,4.664 L7.632,4.664 C7.68,4.432 7.728,4.192 7.76,3.936 L9.328,3.936 L9.328,3.224 L5.336,3.224 L5.336,3.936 L7.016,3.936 C6.984,4.184 6.952,4.424 6.904,4.664 L5.568,4.664 L5.568,8.52 L6.28,8.52 Z M3.136,10.296 C3.584,10.296 3.808,10.048 3.808,9.568 L3.808,6.4 L4.464,6.4 C4.36,6.776 4.24,7.104 4.104,7.384 L4.728,7.624 C4.904,7.272 5.048,6.784 5.176,6.16 L5.176,5.696 L4.232,5.696 C4.136,5.576 4.032,5.448 3.92,5.304 C4.288,4.896 4.632,4.4 4.952,3.816 L4.952,3.224 L2.224,3.224 L2.224,3.928 L4.144,3.928 C3.936,4.256 3.72,4.552 3.48,4.816 C3.32,4.64 3.136,4.456 2.944,4.264 L2.384,4.616 C2.784,5 3.12,5.36 3.408,5.696 L2,5.696 L2,6.4 L3.088,6.4 L3.088,9.392 C3.088,9.568 3.016,9.656 2.888,9.656 C2.664,9.656 2.44,9.64 2.2,9.608 L2.352,10.296 L3.136,10.296 Z M5.376,10.328 C6.16,10.064 6.736,9.696 7.088,9.216 C7.448,8.704 7.648,8.016 7.68,7.152 L7.68,5.736 L6.944,5.736 L6.944,7.152 C6.92,7.8 6.776,8.328 6.512,8.736 C6.232,9.12 5.712,9.432 4.96,9.68 L5.376,10.328 Z M8.88,10.328 L9.408,9.8 C9.024,9.368 8.544,8.928 7.984,8.488 L7.504,8.96 C8.096,9.448 8.552,9.904 8.88,10.328 Z M16.384,10.272 C16.856,10.272 17.096,10.008 17.096,9.496 L17.096,3 L16.384,3 L16.384,9.32 C16.384,9.512 16.296,9.616 16.136,9.616 C15.88,9.616 15.616,9.6 15.344,9.568 L15.504,10.272 L16.384,10.272 Z M11.216,4.664 L11.72,4.16 C11.416,3.8 11.048,3.44 10.608,3.08 L10.088,3.576 C10.576,3.96 10.952,4.328 11.216,4.664 Z M12.576,8.32 L12.576,3.976 L14.072,3.976 L14.072,8.272 L14.744,8.272 L14.744,3.328 L11.904,3.328 L11.904,8.32 L12.576,8.32 Z M15.88,8.6 L15.88,3.656 L15.216,3.656 L15.216,8.6 L15.88,8.6 Z M11.912,10.352 C12.504,10.064 12.936,9.672 13.2,9.16 C13.472,8.608 13.616,7.872 13.64,6.952 L13.64,4.44 L13.016,4.44 L13.016,6.952 C12.992,7.664 12.88,8.24 12.68,8.688 C12.472,9.104 12.088,9.448 11.52,9.72 L11.912,10.352 Z M11.064,6.704 L11.56,6.2 C11.264,5.816 10.904,5.432 10.48,5.04 L9.96,5.536 C10.432,5.952 10.8,6.336 11.064,6.704 Z M10.688,10.24 C11.048,9.376 11.376,8.456 11.664,7.48 L11.024,7.232 C10.736,8.16 10.392,9.064 10,9.944 L10.688,10.24 Z M14.552,10.336 L15.056,9.84 C14.736,9.424 14.352,9.016 13.888,8.6 L13.432,9.04 C13.912,9.504 14.288,9.936 14.552,10.336 Z" id="预测" fill="#FFFFFF" transform="translate(9.548000, 6.676000) scale(-1, 1) translate(-9.548000, -6.676000) "></path> | |||||
| </g> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -0,0 +1,35 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <svg width="24px" height="19px" viewBox="0 0 24 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |||||
| <!-- Generator: Sketch 63.1 (92452) - https://sketch.com --> | |||||
| <title>fp</title> | |||||
| <desc>Created with Sketch.</desc> | |||||
| <defs> | |||||
| <path d="M17.1480906,0.0392739336 L18.3266093,0.00728953835 C18.6341197,-0.00105613749 18.9283586,0.132596377 19.1243929,0.369667804 L20,1.42857143 L20,1.42857143 L10.4761905,1.42857143 L10.4761905,0.0392739336 L17.1480906,0.0392739336 Z" id="path-1"></path> | |||||
| <filter x="-36.8%" y="-174.5%" width="173.5%" height="589.5%" filterUnits="objectBoundingBox" id="filter-2"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| <path d="M1,0 L18.04761,0 C18.5998948,-2.12475365e-16 19.04761,0.44771525 19.04761,1 L19.04761,10.875081 C19.0475959,11.6828644 18.5616641,12.411342 17.8158526,12.721631 C14.1649895,14.2405437 11.4009752,15 9.52380952,15 C7.64664694,15 4.88263611,14.2405461 1.23177702,12.7216384 C0.485941676,12.4113657 9.8926869e-17,11.682874 0,10.8750748 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z" id="path-3"></path> | |||||
| <filter x="-18.4%" y="-16.7%" width="136.8%" height="146.7%" filterUnits="objectBoundingBox" id="filter-4"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| </defs> | |||||
| <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | |||||
| <g id="fp" transform="translate(12.000000, 8.500000) scale(-1, 1) translate(-12.000000, -8.500000) translate(2.000000, 1.000000)"> | |||||
| <g id="Rectangle-34" fill-rule="nonzero"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use> | |||||
| <use fill="#B37B00" xlink:href="#path-1"></use> | |||||
| </g> | |||||
| <g id="Rectangle-34" fill-rule="nonzero"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use> | |||||
| <use fill="#FFAF00" xlink:href="#path-3"></use> | |||||
| </g> | |||||
| <text id="FP" transform="translate(10.000000, 7.000000) scale(-1, 1) translate(-10.000000, -7.000000) " font-family="PingFangSC-Medium, PingFang SC" font-size="8" font-weight="400" line-spacing="12" fill="#FFFFFF"> | |||||
| <tspan x="5" y="9">FP</tspan> | |||||
| </text> | |||||
| </g> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -0,0 +1,33 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <svg width="24px" height="19px" viewBox="0 0 24 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |||||
| <!-- Generator: Sketch 63.1 (92452) - https://sketch.com --> | |||||
| <title>真实</title> | |||||
| <desc>Created with Sketch.</desc> | |||||
| <defs> | |||||
| <path d="M17.1480906,0.0392739336 L18.3266093,0.00728953835 C18.6341197,-0.00105613749 18.9283586,0.132596377 19.1243929,0.369667804 L20,1.42857143 L20,1.42857143 L10.4761905,1.42857143 L10.4761905,0.0392739336 L17.1480906,0.0392739336 Z" id="path-1"></path> | |||||
| <filter x="-36.8%" y="-174.5%" width="173.5%" height="589.5%" filterUnits="objectBoundingBox" id="filter-2"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| <path d="M1,0 L18.04761,0 C18.5998948,-2.12475365e-16 19.04761,0.44771525 19.04761,1 L19.04761,10.875081 C19.0475959,11.6828644 18.5616641,12.411342 17.8158526,12.721631 C14.1649895,14.2405437 11.4009752,15 9.52380952,15 C7.64664694,15 4.88263611,14.2405461 1.23177702,12.7216384 C0.485941676,12.4113657 9.8926869e-17,11.682874 0,10.8750748 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z" id="path-3"></path> | |||||
| <filter x="-18.4%" y="-16.7%" width="136.8%" height="146.7%" filterUnits="objectBoundingBox" id="filter-4"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| </defs> | |||||
| <g id="MindExplain" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | |||||
| <g id="真实" transform="translate(12.000000, 8.500000) scale(-1, 1) translate(-12.000000, -8.500000) translate(2.000000, 1.000000)" fill-rule="nonzero"> | |||||
| <g id="Rectangle-34"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use> | |||||
| <use fill="#007475" xlink:href="#path-1"></use> | |||||
| </g> | |||||
| <g id="Rectangle-34"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use> | |||||
| <use fill="#00A5A7" xlink:href="#path-3"></use> | |||||
| </g> | |||||
| <path d="M8.648,10.488 L9.04,9.888 C8.448,9.568 7.8,9.28 7.088,9.04 L9.12,9.04 L9.12,8.368 L8.104,8.368 L8.104,4.632 L5.864,4.632 C5.896,4.504 5.92,4.368 5.952,4.224 L8.824,4.224 L8.824,3.568 L6.064,3.568 C6.08,3.424 6.104,3.28 6.12,3.12 L5.352,3.016 C5.336,3.192 5.312,3.376 5.28,3.568 L2.296,3.568 L2.296,4.224 L5.176,4.224 C5.152,4.36 5.128,4.496 5.096,4.632 L3.136,4.632 L3.136,8.368 L2,8.368 L2,9.04 L4.112,9.04 C3.584,9.36 2.936,9.632 2.168,9.84 L2.48,10.488 C3.376,10.208 4.136,9.856 4.76,9.424 L4.424,9.04 L6.648,9.04 L6.392,9.432 C7.16,9.688 7.912,10.04 8.648,10.488 Z M7.384,5.592 L3.864,5.592 L3.864,5.232 L7.384,5.232 L7.384,5.592 Z M7.384,6.512 L3.864,6.512 L3.864,6.16 L7.384,6.16 L7.384,6.512 Z M7.384,7.424 L3.864,7.424 L3.864,7.072 L7.384,7.072 L7.384,7.424 Z M7.384,8.368 L3.864,8.368 L3.864,7.984 L7.384,7.984 L7.384,8.368 Z M10.944,5.392 L10.944,4.448 L16.16,4.448 L16.16,5.392 L16.896,5.392 L16.896,3.752 L13.976,3.752 C13.896,3.472 13.808,3.224 13.712,3 L12.936,3.128 C13.032,3.32 13.12,3.528 13.208,3.752 L10.208,3.752 L10.208,5.392 L10.944,5.392 Z M13.248,6.184 L13.64,5.584 C13.176,5.256 12.656,4.976 12.088,4.752 L11.712,5.312 C12.24,5.52 12.752,5.816 13.248,6.184 Z M16.664,10.48 L17.08,9.824 C16.152,9.248 15.136,8.736 14.032,8.304 C14.064,8.24 14.104,8.176 14.144,8.112 L16.968,8.112 L16.968,7.392 L14.456,7.392 C14.616,6.912 14.704,6.376 14.728,5.784 L14.728,4.808 L13.992,4.808 L13.992,5.784 C13.96,6.376 13.848,6.912 13.656,7.392 L10.16,7.392 L10.16,8.112 L13.264,8.112 L13.128,8.296 C12.592,8.904 11.576,9.4 10.088,9.792 L10.504,10.44 C11.928,10.072 12.968,9.544 13.616,8.856 C14.656,9.272 15.672,9.808 16.664,10.48 Z M12.472,7.312 L12.864,6.712 C12.392,6.384 11.872,6.104 11.304,5.872 L10.928,6.44 C11.456,6.648 11.976,6.936 12.472,7.312 Z" fill="#FFFFFF" transform="translate(9.540000, 6.744000) scale(-1, 1) translate(-9.540000, -6.744000) "></path> | |||||
| </g> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -0,0 +1,35 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <svg width="24px" height="19px" viewBox="0 0 24 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |||||
| <!-- Generator: Sketch 63.1 (92452) - https://sketch.com --> | |||||
| <title>tn</title> | |||||
| <desc>Created with Sketch.</desc> | |||||
| <defs> | |||||
| <path d="M17.1480906,0.0392739336 L18.3266093,0.00728953835 C18.6341197,-0.00105613749 18.9283586,0.132596377 19.1243929,0.369667804 L20,1.42857143 L20,1.42857143 L10.4761905,1.42857143 L10.4761905,0.0392739336 L17.1480906,0.0392739336 Z" id="path-1"></path> | |||||
| <filter x="-36.8%" y="-174.5%" width="173.5%" height="589.5%" filterUnits="objectBoundingBox" id="filter-2"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| <path d="M1,0 L18.04761,0 C18.5998948,-2.12475365e-16 19.04761,0.44771525 19.04761,1 L19.04761,10.875081 C19.0475959,11.6828644 18.5616641,12.411342 17.8158526,12.721631 C14.1649895,14.2405437 11.4009752,15 9.52380952,15 C7.64664694,15 4.88263611,14.2405461 1.23177702,12.7216384 C0.485941676,12.4113657 9.8926869e-17,11.682874 0,10.8750748 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z" id="path-3"></path> | |||||
| <filter x="-18.4%" y="-16.7%" width="136.8%" height="146.7%" filterUnits="objectBoundingBox" id="filter-4"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| </defs> | |||||
| <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | |||||
| <g id="tn" transform="translate(12.000000, 8.500000) scale(-1, 1) translate(-12.000000, -8.500000) translate(2.000000, 1.000000)"> | |||||
| <g id="Rectangle-34" fill-rule="nonzero"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use> | |||||
| <use fill="#25419E" xlink:href="#path-1"></use> | |||||
| </g> | |||||
| <g id="Rectangle-34" fill-rule="nonzero"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use> | |||||
| <use fill="#5E7CE0" xlink:href="#path-3"></use> | |||||
| </g> | |||||
| <text id="TN" transform="translate(9.500000, 7.000000) scale(-1, 1) translate(-9.500000, -7.000000) " font-family="PingFangSC-Medium, PingFang SC" font-size="8" font-weight="400" line-spacing="12" fill="#FFFFFF"> | |||||
| <tspan x="4" y="9">TN</tspan> | |||||
| </text> | |||||
| </g> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -0,0 +1,35 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <svg width="24px" height="19px" viewBox="0 0 24 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |||||
| <!-- Generator: Sketch 63.1 (92452) - https://sketch.com --> | |||||
| <title>tp</title> | |||||
| <desc>Created with Sketch.</desc> | |||||
| <defs> | |||||
| <path d="M17.1480906,0.0392739336 L18.3266093,0.00728953835 C18.6341197,-0.00105613749 18.9283586,0.132596377 19.1243929,0.369667804 L20,1.42857143 L20,1.42857143 L10.4761905,1.42857143 L10.4761905,0.0392739336 L17.1480906,0.0392739336 Z" id="path-1"></path> | |||||
| <filter x="-36.8%" y="-174.5%" width="173.5%" height="589.5%" filterUnits="objectBoundingBox" id="filter-2"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| <path d="M1,0 L18.04761,0 C18.5998948,-2.12475365e-16 19.04761,0.44771525 19.04761,1 L19.04761,10.875081 C19.0475959,11.6828644 18.5616641,12.411342 17.8158526,12.721631 C14.1649895,14.2405437 11.4009752,15 9.52380952,15 C7.64664694,15 4.88263611,14.2405461 1.23177702,12.7216384 C0.485941676,12.4113657 9.8926869e-17,11.682874 0,10.8750748 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z" id="path-3"></path> | |||||
| <filter x="-18.4%" y="-16.7%" width="136.8%" height="146.7%" filterUnits="objectBoundingBox" id="filter-4"> | |||||
| <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> | |||||
| <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur> | |||||
| <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix> | |||||
| </filter> | |||||
| </defs> | |||||
| <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | |||||
| <g id="tp" transform="translate(12.000000, 8.500000) scale(-1, 1) translate(-12.000000, -8.500000) translate(2.000000, 1.000000)"> | |||||
| <g id="Rectangle-34" fill-rule="nonzero"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use> | |||||
| <use fill="#1F68A0" xlink:href="#path-1"></use> | |||||
| </g> | |||||
| <g id="Rectangle-34" fill-rule="nonzero"> | |||||
| <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use> | |||||
| <use fill="#6CBFFF" xlink:href="#path-3"></use> | |||||
| </g> | |||||
| <text id="TP" transform="translate(9.500000, 7.000000) scale(-1, 1) translate(-9.500000, -7.000000) " font-family="PingFangSC-Medium, PingFang SC" font-size="8" font-weight="400" line-spacing="12" fill="#FFFFFF"> | |||||
| <tspan x="4" y="9">TP</tspan> | |||||
| </text> | |||||
| </g> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -0,0 +1,200 @@ | |||||
| <!-- | |||||
| Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved. | |||||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| you may not use this file except in compliance with the License. | |||||
| You may obtain a copy of the License at | |||||
| http://www.apache.org/licenses/LICENSE-2.0 | |||||
| Unless required by applicable law or agreed to in writing, software | |||||
| distributed under the License is distributed on an "AS IS" BASIS, | |||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| See the License for the specific language governing permissions and | |||||
| limitations under the License. | |||||
| --> | |||||
| <template> | |||||
| <div ref="evaluationtDom" | |||||
| class="cl-bar-chart"></div> | |||||
| </template> | |||||
| <script type="text/javascript"> | |||||
| import echarts from 'echarts'; | |||||
| export default { | |||||
| name: 'BenchmarkBarChart', | |||||
| props: ['barData', 'theme', 'resizeFlag'], | |||||
| data: function() { | |||||
| return { | |||||
| option: {}, // Chart data | |||||
| echartInstance: null, // Chart instantiation object | |||||
| barStart: 0, // Zoom start value | |||||
| barEnd: 100, // Zoom end value | |||||
| firstInit: true, // Identification of the first load data | |||||
| limitCount: 20, // Limit number of bars | |||||
| legendLimit: 10, // Limit number of characters in legend | |||||
| }; | |||||
| }, | |||||
| mounted: function() { | |||||
| this.initEcharts(); | |||||
| }, | |||||
| watch: { | |||||
| barData: { | |||||
| handler() { | |||||
| this.setSeries(); | |||||
| }, | |||||
| deep: true, | |||||
| }, | |||||
| resizeFlag: { | |||||
| handler() { | |||||
| if (this.echartInstance) { | |||||
| this.echartInstance.resize(); | |||||
| } | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| methods: { | |||||
| /** | |||||
| * Refresh the chart based on the latest data | |||||
| */ | |||||
| setSeries() { | |||||
| const self = this; | |||||
| self.option.series = []; | |||||
| let totalCount = 0; | |||||
| for (let i = 0; i < self.barData.series.length; i++) { | |||||
| self.option.series.push({ | |||||
| name: self.barData.series[i].name, | |||||
| type: 'bar', | |||||
| data: self.barData.series[i].values, | |||||
| }); | |||||
| totalCount += self.barData.series[i].values.length; | |||||
| } | |||||
| if (self.firstInit && totalCount) { | |||||
| self.firstInit = false; | |||||
| if (totalCount > self.limitCount) { | |||||
| const base = (self.limitCount / totalCount) * 100; | |||||
| self.barEnd = base; | |||||
| self.option.dataZoom.forEach((zoommData) => { | |||||
| zoommData.end = self.barEnd; | |||||
| }); | |||||
| } | |||||
| } else if (self.echartInstance) { | |||||
| const optionData = self.echartInstance.getOption(); | |||||
| if (optionData && optionData.dataZoom) { | |||||
| self.option.dataZoom = optionData.dataZoom; | |||||
| } | |||||
| } | |||||
| self.option.legend.data = self.barData.legend; | |||||
| self.option.yAxis.data = self.barData.yAxis; | |||||
| // Charting | |||||
| if (self.echartInstance) { | |||||
| self.echartInstance.setOption(self.option, true); | |||||
| self.echartInstance.resize(); | |||||
| } | |||||
| }, | |||||
| /** | |||||
| * Instantiate the chart object and set the basic parameters | |||||
| */ | |||||
| initEcharts() { | |||||
| const self = this; | |||||
| const dom = this.$refs.evaluationtDom; | |||||
| const theme = self.theme; | |||||
| if (dom) { | |||||
| self.echartInstance = echarts.init(dom, theme); | |||||
| } | |||||
| self.option = { | |||||
| tooltip: { | |||||
| trigger: 'axis', | |||||
| axisPointer: { | |||||
| type: 'shadow', | |||||
| }, | |||||
| }, | |||||
| legend: { | |||||
| orient: 'vertical', | |||||
| data: [], | |||||
| right: 10, | |||||
| formatter: (param) => { | |||||
| let str = ''; | |||||
| if (param.length > self.legendLimit) { | |||||
| const splitCount = Math.ceil(param.length / self.legendLimit); | |||||
| const strArr = []; | |||||
| for (let i = 0; i < splitCount; i++) { | |||||
| const start = i * self.legendLimit; | |||||
| const end = start + self.legendLimit; | |||||
| strArr.push(param.slice(start, end)); | |||||
| } | |||||
| str = strArr.join('\n'); | |||||
| } else { | |||||
| str = param; | |||||
| } | |||||
| return str; | |||||
| }, | |||||
| tooltip: { | |||||
| show: true, | |||||
| formatter: (param) => { | |||||
| const tip = param.name; | |||||
| return tip; | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| grid: { | |||||
| left: '10%', | |||||
| right: 200, | |||||
| bottom: '3%', | |||||
| top: 30, | |||||
| }, | |||||
| xAxis: { | |||||
| type: 'value', | |||||
| position: 'top', | |||||
| boundaryGap: [0, 0.01], | |||||
| name: this.$t('metric.evaluationScore'), | |||||
| }, | |||||
| yAxis: { | |||||
| type: 'category', | |||||
| data: [], | |||||
| inverse: true, | |||||
| }, | |||||
| dataZoom: [ | |||||
| { | |||||
| type: 'inside', | |||||
| filterMode: 'empty', | |||||
| orient: 'vertical', | |||||
| yAxisIndex: 0, | |||||
| start: this.barStart, | |||||
| end: this.barEnd, | |||||
| }, | |||||
| { | |||||
| type: 'slider', | |||||
| filterMode: 'empty', | |||||
| orient: 'vertical', | |||||
| yAxisIndex: 0, | |||||
| start: this.barStart, | |||||
| end: this.barEnd, | |||||
| right: 150, | |||||
| top: 50, | |||||
| bottom: 30, | |||||
| }, | |||||
| ], | |||||
| barGap: '20%', | |||||
| series: [], | |||||
| }; | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss"> | |||||
| .cl-bar-chart { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| } | |||||
| </style> | |||||
| @@ -30,6 +30,7 @@ limitations under the License. | |||||
| mode="horizontal"> | mode="horizontal"> | ||||
| <el-menu-item index="/summary-manage">{{$t("summaryManage.summaryList")}}</el-menu-item> | <el-menu-item index="/summary-manage">{{$t("summaryManage.summaryList")}}</el-menu-item> | ||||
| <el-menu-item index="/debugger">{{$t("debugger.debugger")}}</el-menu-item> | <el-menu-item index="/debugger">{{$t("debugger.debugger")}}</el-menu-item> | ||||
| <el-menu-item index="/explain">{{$t("explain.explain")}}</el-menu-item> | |||||
| </el-menu> | </el-menu> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -189,8 +190,12 @@ export default { | |||||
| // get active menu item | // get active menu item | ||||
| getActive() { | getActive() { | ||||
| const str = this.$route.path.split('/'); | const str = this.$route.path.split('/'); | ||||
| if (str.length > 1 && str[1] === 'debugger') { | |||||
| return this.$route.path; | |||||
| if (str.length > 1) { | |||||
| if (str[1] === 'debugger') { | |||||
| return this.$route.path; | |||||
| } else if (str[1] === 'explain') { | |||||
| return `/${str[1]}`; | |||||
| } | |||||
| } | } | ||||
| return '/summary-manage'; | return '/summary-manage'; | ||||
| }, | }, | ||||
| @@ -0,0 +1,117 @@ | |||||
| <!-- | |||||
| Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved. | |||||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| you may not use this file except in compliance with the License. | |||||
| You may obtain a copy of the License at | |||||
| http://www.apache.org/licenses/LICENSE-2.0 | |||||
| Unless required by applicable law or agreed to in writing, software | |||||
| distributed under the License is distributed on an "AS IS" BASIS, | |||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| See the License for the specific language governing permissions and | |||||
| limitations under the License. | |||||
| --> | |||||
| <template> | |||||
| <div class="cl-superpose-image" | |||||
| :style="{'height': `${containerSize}px`,'width': `${containerSize}px`}"> | |||||
| <!-- <canvas ref="canvas" class="second-level" v-show="ifSuperpose"></canvas> --> | |||||
| <img :src="backgroundImg" | |||||
| class="second-level" | |||||
| v-show="ifSuperpose" | |||||
| v-if="backgroundReady" | |||||
| @error="backgroundError()" | |||||
| :style="{'position': 'absolute', 'top':`${backTop}px`,'left':`${backLeft}px`, | |||||
| 'height': `${imageHeight}px`, 'width':`${imageWidth}px`}"> | |||||
| <div v-if="targetReady" | |||||
| class="first-level-container" | |||||
| :style="{'position': 'absolute', 'top': `${targetTop}px`, 'left':`${targetLeft}px`, | |||||
| 'height': `${imageHeight}px`, 'width':`${imageWidth}px`}"> | |||||
| <img :src="targetImg" | |||||
| class="first-level" | |||||
| :class="!ifSuperpose?'overlay-background':''" | |||||
| @error="targetError()"> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| export default { | |||||
| props: [ | |||||
| 'backgroundImg', // The background at the second level | |||||
| 'targetImg', // The target image at the first level | |||||
| 'ifSuperpose', // If show the canvas of background | |||||
| 'containerSize', // The width and height of container | |||||
| ], | |||||
| data() { | |||||
| return { | |||||
| targetReady: true, // The state of target image | |||||
| backgroundReady: true, // The state of background image | |||||
| targetTop: 0, // top of target | |||||
| targetLeft: 0, // left of target | |||||
| imageHeight: 0, // height of image | |||||
| imageWidth: 0, // width of image | |||||
| backTop: 0, // top of background | |||||
| backLeft: 0, // left of background | |||||
| }; | |||||
| }, | |||||
| created() { | |||||
| this.calImageSize(); | |||||
| }, | |||||
| methods: { | |||||
| /** | |||||
| * The logic of cal image size | |||||
| */ | |||||
| calImageSize() { | |||||
| const backgroundTemp = new Image(); | |||||
| backgroundTemp.src = this.backgroundImg; | |||||
| backgroundTemp.onload = () => { | |||||
| if (backgroundTemp.width > backgroundTemp.height) { | |||||
| this.imageWidth = this.containerSize; | |||||
| this.imageHeight = | |||||
| this.containerSize * (backgroundTemp.height / backgroundTemp.width); | |||||
| this.backTop = this.containerSize / 2 - this.imageHeight / 2; | |||||
| this.targetTop = this.backTop; | |||||
| } else if (backgroundTemp.width < backgroundTemp.height) { | |||||
| this.imageHeight = this.containerSize; | |||||
| this.imageWidth = | |||||
| this.containerSize * (backgroundTemp.width / backgroundTemp.height); | |||||
| this.backLeft = this.containerSize / 2 - this.imageWidth / 2; | |||||
| this.targetLeft = this.backLeft; | |||||
| } else { | |||||
| this.imageWidth = this.containerSize; | |||||
| this.imageHeight = this.containerSize; | |||||
| } | |||||
| }; | |||||
| }, | |||||
| /** | |||||
| * The logic that is executed when target image loading failed | |||||
| */ | |||||
| targetError() { | |||||
| this.targetReady = false; | |||||
| }, | |||||
| /** | |||||
| * The logic that is executed when background image loading failed | |||||
| */ | |||||
| backgroundError() { | |||||
| this.backgroundReady = false; | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .cl-superpose-image { | |||||
| position: relative; | |||||
| overflow: hidden; | |||||
| .first-level-container { | |||||
| & img { | |||||
| height: 100%; | |||||
| width: 100%; | |||||
| object-fit: fill; | |||||
| } | |||||
| } | |||||
| .overlay-background { | |||||
| background: #371956; | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @@ -494,7 +494,7 @@ | |||||
| "curValue": "Current Value", | "curValue": "Current Value", | ||||
| "compareToPre": "Compare with Previous Step", | "compareToPre": "Compare with Previous Step", | ||||
| "stepTip": "(The value 0 indicates the initial training state.)", | "stepTip": "(The value 0 indicates the initial training state.)", | ||||
| "toSummeryList": "Go to Training List", | |||||
| "toSummeryList": "Go to Summary List", | |||||
| "clientIp": "Client IP", | "clientIp": "Client IP", | ||||
| "deviceId": "Device ID", | "deviceId": "Device ID", | ||||
| "currentStep": "Step", | "currentStep": "Step", | ||||
| @@ -508,6 +508,64 @@ | |||||
| "value": "Value", | "value": "Value", | ||||
| "largeDataTip": "The requested data is too large. Try another dimension.", | "largeDataTip": "The requested data is too large. Try another dimension.", | ||||
| "continueTo": "Continue to" | "continueTo": "Continue to" | ||||
| }, | |||||
| "explain": { | |||||
| "explain": "Model Explanation", | |||||
| "explainSummary": "Explanation List", | |||||
| "explainSummaryCurrentFolder": "Root path of the explanation log:", | |||||
| "summaryPath": "Explanation Log Path", | |||||
| "title": "Saliency Map Visualization", | |||||
| "explainMethod": "Explanation Methods", | |||||
| "viewScore": "View Score", | |||||
| "fetch": "Filter", | |||||
| "minConfidence": "Probability Threshold", | |||||
| "imgSort": "Sort Images By", | |||||
| "default": "Default", | |||||
| "byProbability": "Probabilities in descending order", | |||||
| "superposeImg": "Overlay on Original Image", | |||||
| "originalPicture": "Original Image", | |||||
| "forecastTag": "Prediction Tag", | |||||
| "tag": "Tag", | |||||
| "confidence": "Probability", | |||||
| "forecastTagTip": "When the inference image has the correct tag, the following four flags are displayed in the tag row", | |||||
| "TP": "TP: indicates true positive. The tag is a positive sample, and the classification is a positive sample;", | |||||
| "FN": "FN: indicates false negative. The tag is a positive sample, and the classification is a negative sample;", | |||||
| "FP": "FP: indicates false positive. The tag is a negative sample, and the classification is a positive sample;", | |||||
| "TN": "TN: indicates true negative. The tag is a negative sample, and the classification is a negative sample;", | |||||
| "mainTipTitle": "Function description:", | |||||
| "mainTipPartOne":"This function visualizes the basis for model classification. After the to-be-explained model, the image, and the tag are selected, a contribution degree of each pixel in the original image to the selected tag is calculated by using an explanation method, and visualization is performed by using a saliency map similar to a heatmap. A brighter color indicates that the corresponding area contributes more to the selected tag of the model prediction. The darker the color, the smaller the contribution of the area to the selected tag.", | |||||
| "mainTipPartTwo":"A saliency map helps you understand the features related to the specified tag during deep neural network inference. When the inference basis and expectation of a model are different, you can debug the model by referring to the saliency map so that the model can perform inference based on proper features.", | |||||
| "mainTipPartThree":"For details about how to generate saliency maps, see section 3.2 'Local Methods' in", | |||||
| "mainTipPartFour":"https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9050829", | |||||
| "noExplainer":"Select Explanation Method" | |||||
| }, | |||||
| "metric": { | |||||
| "scoreSystem": "Scoring System", | |||||
| "comprehensive": "Comprehensive Assessment", | |||||
| "classify": "Classification Assessment", | |||||
| "singleMethod": "Single method and multiple indicators", | |||||
| "multiMethod": "Single indicator and multiple methods", | |||||
| "interpretation": "Explanation", | |||||
| "measurement": "Measurement", | |||||
| "seeInterpretation": "You are viewing scores of the explanation method ", | |||||
| "seeMeasurement": "You are viewing scores of the measurement method", | |||||
| "showGrade": "of different tag types", | |||||
| "evaluationScore": "Assessment Score", | |||||
| "weightAllocatgion": "Weight Configuration", | |||||
| "compositeScore": "Comprehensive Score", | |||||
| "metric": "Dimension", | |||||
| "inputWeightScore": "Enter a weight score between 0 and 1", | |||||
| "weightSumNotNull": "The sum of weights cannot be empty", | |||||
| "weightError": "Weight calculation error", | |||||
| "weightSum": "The sum of weights must be 1", | |||||
| "radarChart": "Explanation Method Comparison Radar Chart", | |||||
| "comprehensiveTooltip": "The comprehensive assessment provides configurable weights for different scoring dimensions and calculates the comprehensive scores to sort and filter the explanation methods. The explanation method has advantages and disadvantages in different scoring dimensions. You can refer to the description of each dimension, adjust the weight based on the actual requirements, and assess the explanation method with emphasis. By default, weights for each dimension are the same.", | |||||
| "classifyTooltip": "Classification assessment groups datasets by tag and measures the explanation methods based on data with different tags.", | |||||
| "scoreSystemtooltipOne": "Function description:", | |||||
| "scoreSystemtooltiptwo": "The scoring system provides multiple dimensions for scoring explanation methods.", | |||||
| "scoreSystemtooltipthree": "Scoring dimensions:", | |||||
| "scoreSystemtooltipfour": " - Faithfulness: evaluates the faithfulness of the explanation result to the model, that is, whether the saliency map correctly reflects the model classification basis. Modify the corresponding positions in the original image according to a certain rule (for example, from bright to dark) and transfer the modified image to the model for inference in sequence. If the brighter the area of the saliency map is, the greater the impact on the selected tag is, the higher the faithfulness of the interpretation result is. Conversely, the explanation result may not reflect the inference basis of the model. Currently, there are three mainstream solutions: naive faithfulness, insertion AUC, and deletion AUC.", | |||||
| "scoreSystemtooltipfive": " - Localization: uses the bounding box of the dataset to assess the positioning accuracy of the highlighted area in the saliency map. Select an objective and related tag. If the explanation method accurately highlights the area related to the selected tag in the image, the highlighted area should overlap the bounding box of the selected objective. Localization assesses the location capability of the explanation result by assessing the overlapped area of the highlighted area and bounding box." | |||||
| }, | }, | ||||
| "error": { | "error": { | ||||
| "50540000": "System error.", | "50540000": "System error.", | ||||
| @@ -508,6 +508,64 @@ | |||||
| "largeDataTip": "请求的数据过大,请使用其他维度重试。", | "largeDataTip": "请求的数据过大,请使用其他维度重试。", | ||||
| "continueTo": "运行到该节点" | "continueTo": "运行到该节点" | ||||
| }, | }, | ||||
| "explain": { | |||||
| "explain": "模型解释", | |||||
| "explainSummary": "解释列表", | |||||
| "explainSummaryCurrentFolder": "解释日志根路径:", | |||||
| "summaryPath": "解释日志路径", | |||||
| "title": "显著图可视化", | |||||
| "explainMethod": "解释方法", | |||||
| "viewScore": "查看评分", | |||||
| "fetch": "筛选", | |||||
| "minConfidence": "概率阈值", | |||||
| "imgSort": "图片排序", | |||||
| "default": "默认", | |||||
| "byProbability": "概率值降序", | |||||
| "superposeImg": "叠加于原图", | |||||
| "originalPicture": "原始图片", | |||||
| "forecastTag": "预测标签", | |||||
| "tag": "标签", | |||||
| "confidence": "概率", | |||||
| "forecastTagTip": "当推理图片带有正确标签,标签行会显示下列四种旗标", | |||||
| "TP": "TP:代表Ture Positive,标签为正样本,分类为正样本;", | |||||
| "FN": "FN:代表False Negative,标签为正样本,分类为负样本;", | |||||
| "FP": "FP:代表Fasle Positive,标签为负样本,分类为正样本;", | |||||
| "TN": "TN:代表Ture Negative,标签为负样本,分类为负样本;", | |||||
| "mainTipTitle": "功能说明:", | |||||
| "mainTipPartOne":"本功能对模型分类的依据进行可视化。选定待解释模型、图片和标签后,解释方法计算得到原始图像中每个像素对选定标签的贡献度,以类似热力图的显著图进行可视。显著图颜色越亮,表示对应区域对于模型预测选定标签的贡献越多;颜色越暗,该区域对选定标签的贡献越小。", | |||||
| "mainTipPartTwo":"显著图可以帮助我们了解深度神经网络推理时,和指定标签有关系的特征。当模型推理依据和期望不同时,可以参考显著图对模型进行调试,让模型依据合理的特征进行推理。", | |||||
| "mainTipPartThree":"主流生成显著图的解释方法可以参考论文3.2节Local Methods:", | |||||
| "mainTipPartFour":"https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9050829", | |||||
| "noExplainer":"请选择解释方法" | |||||
| }, | |||||
| "metric": { | |||||
| "scoreSystem": "评分体系", | |||||
| "comprehensive": "综合评估", | |||||
| "classify": "分类评估", | |||||
| "singleMethod": "单方法多指标", | |||||
| "multiMethod": "单指标多方法", | |||||
| "interpretation": "解释方法", | |||||
| "measurement": "度量方法", | |||||
| "seeInterpretation": "您正在查看解释方法", | |||||
| "seeMeasurement": "您正在查看度量方法", | |||||
| "showGrade": "在不同标签类型上的分数", | |||||
| "evaluationScore": "评价分数", | |||||
| "weightAllocatgion": "权重配置", | |||||
| "compositeScore": "综合得分", | |||||
| "metric": "评分维度", | |||||
| "inputWeightScore": "请输入权重分数(0-1)", | |||||
| "weightSumNotNull": "权重总和不能为空", | |||||
| "weightError": "权重计算出错", | |||||
| "weightSum": "权重总和必须为1", | |||||
| "radarChart": "解释方法对比雷达图", | |||||
| "comprehensiveTooltip": "综合评估为不同评分维度提供可配置的权重,计算解释方法的综合得分,以便对解释方法进行排序筛选。解释方法在不同评分维度上各有优势,可以参考各个维度的介绍,根据实际需求对权重进行调整,有侧重地评估解释方法。本功能默认对各个维度设置相同的权重。", | |||||
| "classifyTooltip": "分类评估将数据集按照标签进行分组,在不同标签的数据上分别度量解释方法。", | |||||
| "scoreSystemtooltipOne": "功能说明:", | |||||
| "scoreSystemtooltiptwo": "评分体系提供多个维度对解释方法进行评分。", | |||||
| "scoreSystemtooltipthree": "评分维度:", | |||||
| "scoreSystemtooltipfour": " -Faithfulness: 该维度评估解释结果对模型的忠实度,即显著图是否正确反映模型分类依据。给定显著图,按照一定规则(如从亮到暗)对原始图像中的相应位置进行修改,将修改后的图像传给模型依次进行推理,如果显著图越亮的区域对选定标签影响越大,则解释结果忠实度越高;反之,解释结果可能无法反映模型的推理依据。当前有三种主流方案度量解释的faithfulness:Naive Faithfulness,Insertion AUC,Deletion AUC。", | |||||
| "scoreSystemtooltipfive": " -Localization: 该维度借助数据集的bounding box对显著图高亮区域的定位准确性进行评估,选定一组目标和相关标签,如果解释方法准确高亮了图像中和选定标签相关的区域,高亮区域和选定目标的bounding box应当有较大重合度。Localization通过评估高亮区域和bounding box的重合度,对解释结果的定位能力进行评估。" | |||||
| }, | |||||
| "error": { | "error": { | ||||
| "50540000": "系统错误", | "50540000": "系统错误", | ||||
| "50540001": "参数类型错误,请检查请求参数类型是否都符合要求", | "50540001": "参数类型错误,请检查请求参数类型是否都符合要求", | ||||
| @@ -125,5 +125,18 @@ export default new Router({ | |||||
| path: '/debugger', | path: '/debugger', | ||||
| component: () => import('./views/debugger/debugger.vue'), | component: () => import('./views/debugger/debugger.vue'), | ||||
| }, | }, | ||||
| { | |||||
| path: '/explain', | |||||
| component: () => import('./views/explain/summary-list.vue'), | |||||
| }, | |||||
| { | |||||
| path: '/explain/saliency-map', | |||||
| component: () => | |||||
| import('./views/explain/saliency-map.vue'), | |||||
| }, | |||||
| { | |||||
| path: '/explain/xai-metric', | |||||
| component: () => import('./views/explain/xai-metric.vue'), | |||||
| }, | |||||
| ], | ], | ||||
| }); | }); | ||||
| @@ -78,12 +78,18 @@ axios.interceptors.response.use( | |||||
| regardError: ['50545013', '50545014', '5054500D'], | regardError: ['50545013', '50545014', '5054500D'], | ||||
| }; | }; | ||||
| if (ignoreCode.ignoreError.includes(errorCode)) { | |||||
| if (errorData[errorCode]) { | |||||
| Vue.prototype.$message.error(errorData[errorCode]); | |||||
| } | |||||
| setTimeout(()=>{ | |||||
| router.push('/'); | |||||
| }, 3000); | |||||
| return Promise.reject(error); | |||||
| } | |||||
| if ( | if ( | ||||
| path.includes('-dashboard') || | path.includes('-dashboard') || | ||||
| ignoreCode.regardError.includes(errorCode) || | |||||
| (ignoreCode.ignoreError.includes(errorCode) && | |||||
| error.config.headers.ignoreError) | |||||
| ) { | |||||
| ignoreCode.regardError.includes(errorCode)) { | |||||
| return Promise.reject(error); | return Promise.reject(error); | ||||
| } | } | ||||
| if (errorData[errorCode]) { | if (errorData[errorCode]) { | ||||
| @@ -389,4 +389,43 @@ export default { | |||||
| data: params, | data: params, | ||||
| }); | }); | ||||
| }, | }, | ||||
| // explain list | |||||
| getExplainList(params) { | |||||
| return axios({ | |||||
| method: 'get', | |||||
| url: 'v1/mindinsight/explainer/explain-jobs', | |||||
| params: params, | |||||
| }); | |||||
| }, | |||||
| // Explain query train base information | |||||
| queryTrainInfo(params) { | |||||
| return axios({ | |||||
| method: 'get', | |||||
| url: '/v1/mindinsight/explainer/explain-job', | |||||
| params: params, | |||||
| }); | |||||
| }, | |||||
| // Explain query page table information | |||||
| queryPageInfo(params) { | |||||
| return axios({ | |||||
| method: 'post', | |||||
| url: '/v1/mindinsight/explainer/saliency', | |||||
| data: params, | |||||
| }); | |||||
| }, | |||||
| // Explain query similar pictures | |||||
| querySimilarPic(params) { | |||||
| return axios({ | |||||
| method: 'get', | |||||
| url: '/v1/mindinsight/explainer/similar', | |||||
| params: params, | |||||
| }); | |||||
| }, | |||||
| getEvaluation(params) { | |||||
| return axios({ | |||||
| method: 'get', | |||||
| url: 'v1/mindinsight/explainer/evaluation', | |||||
| params: params, | |||||
| }); | |||||
| }, | |||||
| }; | }; | ||||
| @@ -0,0 +1,490 @@ | |||||
| <!-- | |||||
| Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved. | |||||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| you may not use this file except in compliance with the License. | |||||
| You may obtain a copy of the License at | |||||
| http://www.apache.org/licenses/LICENSE-2.0 | |||||
| Unless required by applicable law or agreed to in writing, software | |||||
| distributed under the License is distributed on an "AS IS" BASIS, | |||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| See the License for the specific language governing permissions and | |||||
| limitations under the License. | |||||
| --> | |||||
| <template> | |||||
| <div id="cl-summary-manage"> | |||||
| <div v-show="loading" | |||||
| class="no-data-page"> | |||||
| <div class="no-data-img"> | |||||
| <img :src="require('@/assets/images/nodata.png')" | |||||
| alt="" /> | |||||
| <p class="no-data-text">{{$t("public.dataLoading")}}</p> | |||||
| </div> | |||||
| </div> | |||||
| <div class="cl-summary-manage-container" | |||||
| v-show="!loading"> | |||||
| <div class="cl-title"> | |||||
| <div class="cl-title-left"> | |||||
| <span class="summary-title">{{$t('explain.explainSummary')}}</span> | |||||
| <span>{{$t("symbols.leftbracket")}}</span> | |||||
| <span>{{$t('explain.explainSummaryCurrentFolder')}}</span> | |||||
| <span :title="currentFolder">{{currentFolder}}</span> | |||||
| <span>{{$t("symbols.rightbracket")}}</span> | |||||
| </div> | |||||
| </div> | |||||
| <!--table content area --> | |||||
| <div class="container"> | |||||
| <!-- list table --> | |||||
| <div class="list-table"> | |||||
| <el-table :data="summaryList" | |||||
| stripe | |||||
| height="100%" | |||||
| tooltip-effect="light" | |||||
| class="list-el-table" | |||||
| ref="table"> | |||||
| <el-table-column width="50" | |||||
| type=index | |||||
| :label="$t('summaryManage.sorting')"> | |||||
| </el-table-column> | |||||
| <el-table-column min-width="600" | |||||
| prop="train_id" | |||||
| :label="$t('explain.summaryPath')" | |||||
| show-overflow-tooltip> | |||||
| </el-table-column> | |||||
| <el-table-column width="180" | |||||
| prop="update_time" | |||||
| :label="$t('summaryManage.updateTime')" | |||||
| show-overflow-tooltip> | |||||
| </el-table-column> | |||||
| <!--operate --> | |||||
| <el-table-column prop="operate" | |||||
| :label="$t('summaryManage.operation')" | |||||
| class-name="operate-container" | |||||
| :width="operateWidth"> | |||||
| <template slot-scope="scope"> | |||||
| <span class="menu-item operate-btn first-btn" | |||||
| @contextmenu.prevent="rightClick(scope.row, $event, 0)" | |||||
| @click.stop="goToSaliencyMap(scope.row)"> | |||||
| {{$t('explain.title')}} </span> | |||||
| <!-- <span class="menu-item operate-btn" | |||||
| @contextmenu.prevent="rightClick(scope.row, $event, 1)" | |||||
| @click.stop="goToConterfactualinterpretation(scope.row)"> | |||||
| {{$t('explain.conterfactualInterpretation')}} </span> --> | |||||
| </template> | |||||
| </el-table-column> | |||||
| </el-table> | |||||
| </div> | |||||
| </div> | |||||
| <!-- outer Page --> | |||||
| <div class="pagination-content"> | |||||
| <el-pagination @current-change="currentPageChange" | |||||
| :current-page="pagination.currentPage" | |||||
| :page-size="pagination.pageSize" | |||||
| :layout="pagination.layout" | |||||
| :total="pagination.total" | |||||
| class="page"> | |||||
| </el-pagination> | |||||
| </div> | |||||
| </div> | |||||
| <div id="contextMenu" | |||||
| v-if="contextMenu.show" | |||||
| :style="{left: contextMenu.left, top: contextMenu.top}"> | |||||
| <ul> | |||||
| <li @click="doRightClick()">{{$t('summaryManage.openNewTab')}}</li> | |||||
| </ul> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import RequestService from '../../services/request-service'; | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| loading: true, | |||||
| currentFolder: '--', | |||||
| // table filter condition | |||||
| summaryList: [], | |||||
| pagination: { | |||||
| currentPage: 1, | |||||
| pageSize: 16, | |||||
| total: 0, | |||||
| layout: 'total, prev, pager, next, jumper', | |||||
| }, | |||||
| contextMenu: { | |||||
| show: false, | |||||
| left: '', | |||||
| top: '', | |||||
| data: null, | |||||
| type: 0, | |||||
| }, | |||||
| tableDom: null, | |||||
| operateWidth: localStorage.getItem('milang') === 'en-us' ? 230 : 145, | |||||
| }; | |||||
| }, | |||||
| computed: {}, | |||||
| watch: {}, | |||||
| destroyed() { | |||||
| window.removeEventListener('resize', this.closeMenu); | |||||
| window.removeEventListener('mousewheel', this.closeMenu); | |||||
| if (this.tableDom) { | |||||
| this.tableDom.removeEventListener('scroll', this.closeMenu); | |||||
| } | |||||
| document.onclick = null; | |||||
| document.onscroll = null; | |||||
| }, | |||||
| activated() {}, | |||||
| mounted() { | |||||
| document.title = `${this.$t('explain.explain')}-MindInsight`; | |||||
| this.$nextTick(() => { | |||||
| this.init(); | |||||
| }); | |||||
| setTimeout(() => { | |||||
| window.addEventListener('resize', this.closeMenu, false); | |||||
| window.addEventListener('mousewheel', this.closeMenu, false); | |||||
| this.tableDom = this.$refs.table.bodyWrapper; | |||||
| if (this.tableDom) { | |||||
| this.tableDom.addEventListener('scroll', this.closeMenu, false); | |||||
| } | |||||
| }, 300); | |||||
| }, | |||||
| methods: { | |||||
| init() { | |||||
| document.onclick = () => { | |||||
| this.contextMenu.show = false; | |||||
| }; | |||||
| document.onscroll = () => { | |||||
| this.contextMenu.show = false; | |||||
| }; | |||||
| const params = { | |||||
| limit: this.pagination.pageSize, | |||||
| offset: this.pagination.currentPage - 1, | |||||
| }; | |||||
| this.querySummaryList(params); | |||||
| }, | |||||
| /** | |||||
| * Querying summary list | |||||
| * @param {Object} params page info param | |||||
| */ | |||||
| querySummaryList(params) { | |||||
| RequestService.getExplainList(params) | |||||
| .then( | |||||
| (res) => { | |||||
| this.loading = false; | |||||
| if (res && res.data && res.data.explain_jobs) { | |||||
| const summaryList = JSON.parse( | |||||
| JSON.stringify(res.data.explain_jobs), | |||||
| ); | |||||
| summaryList.forEach((i) => { | |||||
| i.update_time = i.update_time ? i.update_time : '--'; | |||||
| }); | |||||
| this.currentFolder = res.data.name ? res.data.name : '--'; | |||||
| this.pagination.total = res.data.total; | |||||
| this.summaryList = summaryList; | |||||
| } else { | |||||
| this.currentFolder = '--'; | |||||
| this.pagination.total = 0; | |||||
| this.summaryList = []; | |||||
| } | |||||
| }, | |||||
| (error) => { | |||||
| this.loading = false; | |||||
| }, | |||||
| ) | |||||
| .catch((e) => { | |||||
| this.loading = false; | |||||
| }); | |||||
| }, | |||||
| currentPageChange(currentPage) { | |||||
| this.pagination.currentPage = currentPage; | |||||
| const params = { | |||||
| offset: this.pagination.currentPage - 1, | |||||
| limit: this.pagination.pageSize, | |||||
| }; | |||||
| this.querySummaryList(params); | |||||
| }, | |||||
| /** | |||||
| * go to train dashboard | |||||
| * @param {Object} row select row | |||||
| */ | |||||
| goToSaliencyMap(row) { | |||||
| this.contextMenu.show = false; | |||||
| const trainId = encodeURIComponent(row.train_id); | |||||
| this.$router.push({ | |||||
| path: '/explain/saliency-map', | |||||
| query: {id: trainId}, | |||||
| }); | |||||
| }, | |||||
| /** | |||||
| * go to Profiler | |||||
| * @param {Object} row select row | |||||
| */ | |||||
| // goToConterfactualinterpretation(row) { | |||||
| // this.contextMenu.show = false; | |||||
| // const profilerDir = encodeURIComponent(row.profiler_dir); | |||||
| // const trainId = encodeURIComponent(row.train_id); | |||||
| // const path = encodeURIComponent(row.relative_path); | |||||
| // const router = '/explain/conterfactual-interpretation'; | |||||
| // this.$router.push({ | |||||
| // path: router, | |||||
| // query: { | |||||
| // dir: profilerDir, | |||||
| // id: trainId, | |||||
| // path: path, | |||||
| // }, | |||||
| // }); | |||||
| // }, | |||||
| rightClick(row, event, type) { | |||||
| const maxWidth = 175; | |||||
| this.contextMenu.data = row; | |||||
| this.contextMenu.type = type; | |||||
| const width = document.getElementById('cl-summary-manage').clientWidth; | |||||
| const left = Math.min(width - maxWidth, event.clientX + window.scrollX); | |||||
| this.contextMenu.left = left + 'px'; | |||||
| this.contextMenu.top = event.clientY + window.scrollY + 'px'; | |||||
| this.contextMenu.show = true; | |||||
| }, | |||||
| doRightClick(key) { | |||||
| const row = this.contextMenu.data; | |||||
| if (!row) { | |||||
| return; | |||||
| } | |||||
| if (this.contextMenu.type) { | |||||
| this.contextMenu.show = false; | |||||
| const profilerDir = encodeURIComponent(row.profiler_dir); | |||||
| const trainId = encodeURIComponent(row.train_id); | |||||
| const path = encodeURIComponent(row.relative_path); | |||||
| const router = '/explain/conterfactual-interpretation'; | |||||
| const routeUrl = this.$router.resolve({ | |||||
| path: router, | |||||
| query: { | |||||
| dir: profilerDir, | |||||
| id: trainId, | |||||
| path: path, | |||||
| }, | |||||
| }); | |||||
| window.open(routeUrl.href, '_blank'); | |||||
| } else { | |||||
| this.contextMenu.show = false; | |||||
| const trainId = encodeURIComponent(row.train_id); | |||||
| const routeUrl = this.$router.resolve({ | |||||
| path: '/explain/saliency-map', | |||||
| query: {id: trainId}, | |||||
| }); | |||||
| window.open(routeUrl.href, '_blank'); | |||||
| } | |||||
| }, | |||||
| closeMenu() { | |||||
| this.contextMenu.show = false; | |||||
| }, | |||||
| /** | |||||
| * tree data | |||||
| * @param {Object} tree | |||||
| * @param {Object} treeNode | |||||
| * @param {Object} resolve | |||||
| */ | |||||
| loadDataListChildren(tree, treeNode, resolve) { | |||||
| setTimeout(() => { | |||||
| resolve(tree.children); | |||||
| }); | |||||
| }, | |||||
| }, | |||||
| components: {}, | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss"> | |||||
| #cl-summary-manage { | |||||
| height: 100%; | |||||
| width: 100%; | |||||
| background-color: #fff; | |||||
| .no-data-page { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| .no-data-img { | |||||
| background: #fff; | |||||
| text-align: center; | |||||
| height: 200px; | |||||
| width: 310px; | |||||
| margin: auto; | |||||
| img { | |||||
| max-width: 100%; | |||||
| } | |||||
| p { | |||||
| font-size: 16px; | |||||
| padding-top: 10px; | |||||
| } | |||||
| } | |||||
| } | |||||
| .cl-summary-manage-container { | |||||
| height: 100%; | |||||
| padding: 14px 32px 32px; | |||||
| } | |||||
| .cl-title { | |||||
| border: none; | |||||
| height: 55px; | |||||
| line-height: 75px; | |||||
| } | |||||
| .cl-title-left { | |||||
| padding-left: 0; | |||||
| height: 55px; | |||||
| line-height: 55px; | |||||
| } | |||||
| .summary-title { | |||||
| font-size: 20px; | |||||
| font-weight: bold; | |||||
| margin-right: 15px; | |||||
| } | |||||
| .summary-subtitle { | |||||
| margin-left: 20px; | |||||
| } | |||||
| .container { | |||||
| height: calc(100% - 97px); | |||||
| overflow-y: auto; | |||||
| .list-table { | |||||
| height: 100%; | |||||
| .operate-container { | |||||
| padding-right: 32px; | |||||
| } | |||||
| } | |||||
| } | |||||
| .pagination-content { | |||||
| margin-top: 16px; | |||||
| text-align: right; | |||||
| } | |||||
| .operate-btn { | |||||
| margin-left: 20px; | |||||
| padding: 12px 0; | |||||
| } | |||||
| .el-dialog { | |||||
| min-width: 500px; | |||||
| padding-bottom: 30px; | |||||
| } | |||||
| .operate-btn.button-disable { | |||||
| -moz-user-select: none; /*Firefox*/ | |||||
| -webkit-user-select: none; /*webkitbrowser*/ | |||||
| -ms-user-select: none; /*IE10*/ | |||||
| -khtml-user-select: none; /*Early browser*/ | |||||
| user-select: none; | |||||
| color: rgb(192, 196, 204); | |||||
| cursor: not-allowed; | |||||
| } | |||||
| .menu-item { | |||||
| color: #00a5a7; | |||||
| cursor: pointer; | |||||
| } | |||||
| .menu-item.operate-btn.first-btn { | |||||
| margin-left: 0; | |||||
| } | |||||
| #contextMenu { | |||||
| position: absolute; | |||||
| min-width: 150px; | |||||
| border: 1px solid #d4d4d4; | |||||
| ul { | |||||
| background-color: #f7faff; | |||||
| border-radius: 2px; | |||||
| li { | |||||
| padding: 5px 18px; | |||||
| cursor: pointer; | |||||
| &:hover { | |||||
| background-color: rgb(167, 167, 167); | |||||
| color: white; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .details-data-list { | |||||
| .el-table td, | |||||
| .el-table th.is-leaf { | |||||
| border: none; | |||||
| border-top: 1px solid #ebeef5; | |||||
| } | |||||
| .el-table { | |||||
| th { | |||||
| padding: 10px 0; | |||||
| border-top: 1px solid #ebeef5; | |||||
| .cell { | |||||
| border-left: 1px solid #d9d8dd; | |||||
| height: 14px; | |||||
| line-height: 14px; | |||||
| } | |||||
| } | |||||
| th:first-child { | |||||
| .cell { | |||||
| border-left: none; | |||||
| } | |||||
| } | |||||
| th:nth-child(2), | |||||
| td:nth-child(2) { | |||||
| max-width: 30%; | |||||
| } | |||||
| td { | |||||
| padding: 8px 0; | |||||
| } | |||||
| } | |||||
| .el-table__row--level-0 td:first-child:after { | |||||
| width: 20px; | |||||
| height: 1px; | |||||
| background: #ebeef5; | |||||
| z-index: 11; | |||||
| position: absolute; | |||||
| left: 0; | |||||
| bottom: -1px; | |||||
| content: ''; | |||||
| display: block; | |||||
| } | |||||
| .el-table__row--level-1 { | |||||
| td { | |||||
| padding: 4px 0; | |||||
| position: relative; | |||||
| } | |||||
| td:first-child::before { | |||||
| width: 42px; | |||||
| background: #f0fdfd; | |||||
| border-right: 2px #00a5a7 solid; | |||||
| z-index: 10; | |||||
| position: absolute; | |||||
| left: 0; | |||||
| top: -1px; | |||||
| bottom: 0px; | |||||
| content: ''; | |||||
| display: block; | |||||
| } | |||||
| } | |||||
| .el-table__row--level-1:first-child { | |||||
| td:first-child::before { | |||||
| bottom: 0; | |||||
| } | |||||
| } | |||||
| .el-dialog__title { | |||||
| font-weight: bold; | |||||
| } | |||||
| .el-dialog__body { | |||||
| max-height: 500px; | |||||
| padding-top: 10px; | |||||
| padding-bottom: 0px; | |||||
| overflow: auto; | |||||
| .details-data-title { | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> | |||||
| @@ -0,0 +1,827 @@ | |||||
| <!-- | |||||
| Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved. | |||||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| you may not use this file except in compliance with the License. | |||||
| You may obtain a copy of the License at | |||||
| http://www.apache.org/licenses/LICENSE-2.0 | |||||
| Unless required by applicable law or agreed to in writing, software | |||||
| distributed under the License is distributed on an "AS IS" BASIS, | |||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| See the License for the specific language governing permissions and | |||||
| limitations under the License. | |||||
| --> | |||||
| <template> | |||||
| <div class="cl-xai"> | |||||
| <div class="cl-xai-title"> | |||||
| <div class="cl-xai-title-left">{{$t('metric.scoreSystem')}} | |||||
| <el-tooltip effect="light" | |||||
| class="item" | |||||
| placement="top-start"> | |||||
| <div slot="content" | |||||
| class="tooltip-container"> | |||||
| <div class="tooltip-style"> | |||||
| <div class="tooltip-title">{{$t('metric.scoreSystemtooltipOne')}}</div> | |||||
| <div class="tooltip-content">{{$t('metric.scoreSystemtooltiptwo')}}</div><br /> | |||||
| <div class="tooltip-title">{{$t('metric.scoreSystemtooltipthree')}}</div> | |||||
| <div class="tooltip-content">{{$t('metric.scoreSystemtooltipfour')}}</div> | |||||
| <div class="tooltip-content">{{$t('metric.scoreSystemtooltipfive')}}</div> | |||||
| </div> | |||||
| </div> | |||||
| <i class="el-icon-info"></i> | |||||
| </el-tooltip> | |||||
| </div> | |||||
| <div class="cl-xai-title-right"> | |||||
| <div class="cl-close-btn" | |||||
| @click="jumpToSaliencyMap"> | |||||
| <img src="@/assets/images/close-page.png"> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <el-tabs v-model="tabType"> | |||||
| <el-tab-pane name="overall"> | |||||
| <span slot="label"> | |||||
| {{$t('metric.comprehensive')}} | |||||
| <el-tooltip effect="light" | |||||
| class="item" | |||||
| placement="top-start"> | |||||
| <div slot="content" | |||||
| class="tooltip-container"> | |||||
| {{$t('metric.comprehensiveTooltip')}} | |||||
| </div> | |||||
| <i class="el-icon-info"></i> | |||||
| </el-tooltip> | |||||
| </span> | |||||
| </el-tab-pane> | |||||
| <el-tab-pane name="detail"> | |||||
| <span slot="label"> | |||||
| {{$t('metric.classify')}} | |||||
| <el-tooltip effect="light" | |||||
| class="item" | |||||
| placement="top-start"> | |||||
| <div slot="content" | |||||
| class="tooltip-container"> | |||||
| {{$t('metric.classifyTooltip')}} | |||||
| </div> | |||||
| <i class="el-icon-info"></i> | |||||
| </el-tooltip> | |||||
| </span> | |||||
| </el-tab-pane> | |||||
| </el-tabs> | |||||
| <div class="cl-xai-con comprehensiveEvaluation" | |||||
| ref="xaiCon" | |||||
| v-show="tabType==='overall' && !isNoData"> | |||||
| <el-table :data="evaluationTableData" | |||||
| border | |||||
| header-row-class-name="evaluation-table-header" | |||||
| show-summary | |||||
| :summary-method="getSummaries" | |||||
| :sum-text="$t('metric.compositeScore')" | |||||
| ref="sortTable"> | |||||
| <el-table-column prop="metric" | |||||
| :label="$t('metric.metric')" | |||||
| width="180" | |||||
| class-name="firstColumn" | |||||
| fixed | |||||
| :resizable="false"> | |||||
| </el-table-column> | |||||
| <el-table-column prop="weight" | |||||
| :label="$t('metric.weightAllocatgion')" | |||||
| width="180" | |||||
| :class-name="!resultShow ? 'resultFalse':''" | |||||
| fixed | |||||
| :resizable="false"> | |||||
| <template slot-scope="scope"> | |||||
| <el-input-number v-model="scope.row.weight" | |||||
| controls-position="right" | |||||
| @change="weightChange" | |||||
| :min="0" | |||||
| :max="1" | |||||
| :precision="2" | |||||
| size="small" | |||||
| :step="0.01"></el-input-number> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column v-for="(item,index) in tableHead" | |||||
| :key="index" | |||||
| :prop="item" | |||||
| sortable | |||||
| min-width="120" | |||||
| :resizable="false"> | |||||
| <template slot="header"> | |||||
| <div :title="item" | |||||
| class="thTooltip">{{item}}</div> | |||||
| </template> | |||||
| </el-table-column> | |||||
| </el-table> | |||||
| </div> | |||||
| <div class="cl-xai-con" | |||||
| v-show="tabType==='detail' && !isNoData"> | |||||
| <div class="classify-container"> | |||||
| <!-- Single method and multi metrics--> | |||||
| <div class="half-item left-item"> | |||||
| <div class="operate-container"> | |||||
| <div class="container-name">{{$t("metric.singleMethod")}}</div> | |||||
| <div class="select-see"> | |||||
| <span class="see-methods">{{$t("metric.seeInterpretation")}}</span> | |||||
| <span class="slectMethod">{{multiMetricForm.selectedMethods}}</span> | |||||
| <span class="see-methods">{{$t('metric.showGrade')}}</span> | |||||
| </div> | |||||
| <div> | |||||
| <span class="select-name">{{$t('metric.interpretation')}}</span> | |||||
| <span> | |||||
| <el-select v-model="multiMetricForm.selectedMethods" | |||||
| :placeholder="$t('metric.interpretation')" | |||||
| @change="getSingalMethodChartData"> | |||||
| <el-option v-for="(item, index) in classifyAllMethods" | |||||
| :key="index" | |||||
| :value="item" | |||||
| :label="item"></el-option> | |||||
| </el-select> | |||||
| </span> | |||||
| </div> | |||||
| <div class="methods-show"> | |||||
| <span class="show-name">{{$t('metric.measurement')}}</span> | |||||
| <span> | |||||
| <el-checkbox-group v-model="multiMetricForm.selectedMetrics" | |||||
| @change="getSingalMethodChartData"> | |||||
| <el-checkbox v-for="(item, index) in classifyAllMetrics" | |||||
| :key="index" | |||||
| :value="item" | |||||
| :label="item"></el-checkbox> | |||||
| </el-checkbox-group> | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| <div class="chart-container"> | |||||
| <benchmark-bar-chart v-bind:barData="multiMetricData" | |||||
| v-bind:resizeFlag="resizeFlag"></benchmark-bar-chart> | |||||
| </div> | |||||
| </div> | |||||
| <!-- Single metric and multi methods --> | |||||
| <div class="half-item right-itemm"> | |||||
| <div class="operate-container"> | |||||
| <div class="container-name">{{$t("metric.multiMethod")}}</div> | |||||
| <div class="select-see"> | |||||
| <span class="see-methods">{{$t("metric.seeMeasurement")}}</span> | |||||
| <span class="slectMethod">{{multiMethodForm.selectedMetrics}} | |||||
| </span> | |||||
| <span class="see-methods">{{$t('metric.showGrade')}}</span> | |||||
| </div> | |||||
| <div> | |||||
| <span class="select-name">{{$t('metric.measurement')}}</span> | |||||
| <span> | |||||
| <el-select v-model="multiMethodForm.selectedMetrics" | |||||
| :placeholder="$t('metric.measurement')" | |||||
| @change="getSingalMetricChartData"> | |||||
| <el-option v-for="(item, index) in classifyAllMetrics" | |||||
| :key="index" | |||||
| :value="item" | |||||
| :label="item"></el-option> | |||||
| </el-select> | |||||
| </span> | |||||
| </div> | |||||
| <div class="methods-show"> | |||||
| <span class="show-name">{{$t('metric.interpretation')}}</span> | |||||
| <span> | |||||
| <el-checkbox-group v-model="multiMethodForm.selectedMethods" | |||||
| @change="getSingalMetricChartData"> | |||||
| <el-checkbox v-for="(item, index) in classifyAllMethods" | |||||
| :key="index" | |||||
| :value="item" | |||||
| :label="item"></el-checkbox> | |||||
| </el-checkbox-group> | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| <div class="chart-container"> | |||||
| <benchmark-bar-chart v-bind:barData="multiMethodData" | |||||
| v-bind:resizeFlag="resizeFlag" | |||||
| theme="light"></benchmark-bar-chart> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <!-- No data --> | |||||
| <div class="cl-xai-con" | |||||
| v-show="isNoData"> | |||||
| <div class="image-noData"> | |||||
| <div> | |||||
| <img :src="require('@/assets/images/nodata.png')" | |||||
| alt="" /> | |||||
| </div> | |||||
| <div v-if="initOver" | |||||
| class="noData-text">{{$t("public.noData")}}</div> | |||||
| <div v-else | |||||
| class="noData-text">{{$t("public.dataLoading")}}</div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| import BenchmarkBarChart from '@/components/benchmarkBarChart'; | |||||
| import RequestService from '../../services/request-service'; | |||||
| export default { | |||||
| components: { | |||||
| BenchmarkBarChart, | |||||
| }, | |||||
| data() { | |||||
| return { | |||||
| trainId: this.$route.query.id, // Train id | |||||
| tabType: 'overall', | |||||
| tableHead: [], // Table head | |||||
| evaluationTableData: [], // Evaluation table data | |||||
| tableParam: {}, // Table param | |||||
| resultShow: true, // Result show | |||||
| isNoData: true, // Is no data | |||||
| initOver: false, // Initialization completion flag | |||||
| fullDict: {}, // Full data dictionary | |||||
| classifyAllMethods: [], // all explain methods | |||||
| // The currently selected exlpain method and all selected metrics | |||||
| multiMetricForm: { | |||||
| selectedMethods: null, | |||||
| selectedMetrics: [], | |||||
| }, | |||||
| // Chart data of current single method | |||||
| multiMetricData: { | |||||
| legend: [], | |||||
| yAxis: [], | |||||
| series: [], | |||||
| }, | |||||
| classifyAllMetrics: [], // all explain metrics | |||||
| // The currently selected metric and all selected exlpain methods | |||||
| multiMethodForm: { | |||||
| selectedMethods: [], | |||||
| selectedMetrics: null, | |||||
| }, | |||||
| // Chart data of current single metric | |||||
| multiMethodData: { | |||||
| legend: [], | |||||
| yAxis: [], | |||||
| series: [], | |||||
| }, | |||||
| allLabels: [], // all labels | |||||
| resizeFlag: false, // Chart drawing area change sign | |||||
| resizeTimer: null, // Chart redraw delay indicator | |||||
| }; | |||||
| }, | |||||
| watch: { | |||||
| // Listen to the current tab | |||||
| tabType(val) { | |||||
| if (val === 'detail') { | |||||
| this.$nextTick(() => { | |||||
| this.resizeFlag = !this.resizeFlag; | |||||
| }); | |||||
| } | |||||
| }, | |||||
| }, | |||||
| destroyed() { | |||||
| // Cancel delay and monitor | |||||
| if (this.resizeTimer) { | |||||
| clearTimeout(this.resizeTimer); | |||||
| this.resizeTimer = null; | |||||
| } | |||||
| window.removeEventListener('resize', this.resizeCallback); | |||||
| }, | |||||
| mounted() { | |||||
| if (!this.trainId) { | |||||
| this.$message.error(this.$t('trainingDashboard.invalidId')); | |||||
| document.title = `${this.$t('metric.scoreSystem')}-MindInsight`; | |||||
| return; | |||||
| } | |||||
| document.title = `${this.$t('metric.scoreSystem')}-MindInsight`; | |||||
| this.getEvaluationData(); | |||||
| window.addEventListener('resize', this.resizeCallback, false); | |||||
| }, | |||||
| methods: { | |||||
| /** | |||||
| * Jump back to train dashboard | |||||
| */ | |||||
| jumpToSaliencyMap() { | |||||
| this.$router.push({ | |||||
| path: '/explain/saliency-map', | |||||
| query: { | |||||
| id: this.trainId, | |||||
| }, | |||||
| }); | |||||
| }, | |||||
| /** | |||||
| * Init evaluation table | |||||
| * @param {Object} res Original data | |||||
| */ | |||||
| initEvaluationTable(res) { | |||||
| if (res && res.explainer_scores && res.explainer_scores.length > 0) { | |||||
| const tableData = []; | |||||
| const resData = res.explainer_scores[0].evaluations; | |||||
| let score = 0; | |||||
| resData.forEach((item, index) => { | |||||
| const data = {}; | |||||
| res.explainer_scores.forEach((v, i) => { | |||||
| data.metric = item.metric; | |||||
| data[v.explainer] = v.evaluations[index].score; | |||||
| }); | |||||
| const resDataLength = resData.length; | |||||
| if (index < resDataLength - 1) { | |||||
| data.weight = Math.floor((1 / resDataLength) * 100) / 100; | |||||
| score += Math.floor((1 / resDataLength) * 100) / 100; | |||||
| } else { | |||||
| score = 1 - score; | |||||
| data.weight = score; | |||||
| } | |||||
| tableData.push(data); | |||||
| }); | |||||
| const tableHead = []; | |||||
| Object.keys(tableData[0]).forEach((item) => { | |||||
| if (item !== 'metric' && item !== 'weight') { | |||||
| tableHead.push(item); | |||||
| } | |||||
| }); | |||||
| this.evaluationTableData = tableData; | |||||
| this.tableHead = tableHead; | |||||
| } | |||||
| }, | |||||
| /** | |||||
| * Weight change | |||||
| */ | |||||
| weightChange() { | |||||
| this.getSummaries(this.tableParam); | |||||
| }, | |||||
| /** | |||||
| * Get summaries | |||||
| * @param {Object} param params | |||||
| * @return {Object} Summaries data | |||||
| */ | |||||
| getSummaries(param) { | |||||
| this.tableParam = param; | |||||
| const {columns, data} = param; | |||||
| if (!this.evaluationTableData.length) { | |||||
| return []; | |||||
| } | |||||
| const sums = []; | |||||
| columns.forEach((column, index) => { | |||||
| const values = data.map((item) => Number(item[column.property])); | |||||
| if (index === 0) { | |||||
| sums[index] = this.$t('metric.compositeScore'); | |||||
| } else if (index === 1) { | |||||
| sums[index] = 0; | |||||
| values.forEach((value) => { | |||||
| sums[index] += value; | |||||
| }); | |||||
| if (sums[index] !== 1) { | |||||
| this.resultShow = false; | |||||
| sums[index] = this.$t('metric.weightSum'); | |||||
| } else { | |||||
| this.resultShow = true; | |||||
| } | |||||
| } else { | |||||
| if (this.resultShow) { | |||||
| sums[index] = 0; | |||||
| values.forEach((value, i) => { | |||||
| const tableData = this.$refs.sortTable.tableData; | |||||
| sums[index] += value * tableData[i].weight; | |||||
| }); | |||||
| sums[index] = Math.floor(sums[index] * 100) / 100; | |||||
| } else { | |||||
| sums[index] = '-'; | |||||
| } | |||||
| } | |||||
| }); | |||||
| return sums; | |||||
| }, | |||||
| /** | |||||
| * Get evaluation data | |||||
| */ | |||||
| getEvaluationData() { | |||||
| const params = { | |||||
| train_id: decodeURIComponent(this.trainId), | |||||
| }; | |||||
| RequestService.getEvaluation(params).then( | |||||
| (res) => { | |||||
| this.initOver = true; | |||||
| if (res && res.data) { | |||||
| const resData = JSON.parse(JSON.stringify(res.data)); | |||||
| if ( | |||||
| resData.explainer_scores.length && | |||||
| resData.explainer_scores[0].evaluations.length | |||||
| ) { | |||||
| this.isNoData = false; | |||||
| this.initEvaluationTable(resData); | |||||
| this.initializeClassifyData(resData); | |||||
| } else { | |||||
| this.isNoData = true; | |||||
| } | |||||
| } | |||||
| }, | |||||
| (err) => { | |||||
| this.initOver = true; | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| /** | |||||
| * Initialize classification evaluation data | |||||
| * @param {Object} oriData Original data | |||||
| */ | |||||
| initializeClassifyData(oriData) { | |||||
| if (!oriData || !oriData.explainer_scores) { | |||||
| this.clearCllassifyCommonData(); | |||||
| return; | |||||
| } | |||||
| const fullDataDict = {}; | |||||
| const classifyAllMethods = []; | |||||
| const classifyAllMetrics = []; | |||||
| const metricsDic = {}; | |||||
| const labelDic = {}; | |||||
| const allLabels = []; | |||||
| // Simplify data to dictionary | |||||
| oriData.explainer_scores.forEach((explainerScore) => { | |||||
| const curMethod = explainerScore.explainer; | |||||
| if (!fullDataDict[curMethod]) { | |||||
| classifyAllMethods.push(curMethod); | |||||
| fullDataDict[curMethod] = {}; | |||||
| explainerScore.class_scores.forEach((classScore) => { | |||||
| const curLabel = classScore.label; | |||||
| if (!labelDic[curLabel]) { | |||||
| labelDic[curLabel] = true; | |||||
| allLabels.push(curLabel); | |||||
| } | |||||
| if (!fullDataDict[curMethod][curLabel]) { | |||||
| fullDataDict[curMethod][curLabel] = {}; | |||||
| classScore.evaluations.forEach((evaluation) => { | |||||
| fullDataDict[curMethod][curLabel][evaluation.metric] = | |||||
| evaluation.score; | |||||
| if (!metricsDic[evaluation.metric]) { | |||||
| metricsDic[evaluation.metric] = true; | |||||
| classifyAllMetrics.push(evaluation.metric); | |||||
| } | |||||
| }); | |||||
| } | |||||
| }); | |||||
| } | |||||
| }); | |||||
| this.fullDict = fullDataDict; | |||||
| this.classifyAllMethods = classifyAllMethods; | |||||
| this.classifyAllMetrics = classifyAllMetrics; | |||||
| this.multiMetricForm.selectedMetrics = classifyAllMetrics; | |||||
| this.multiMethodForm.selectedMethods = classifyAllMethods; | |||||
| this.allLabels = allLabels; | |||||
| if (classifyAllMethods.length) { | |||||
| this.multiMetricForm.selectedMethods = classifyAllMethods[0]; | |||||
| } | |||||
| if (classifyAllMetrics.length) { | |||||
| this.multiMethodForm.selectedMetrics = classifyAllMetrics[0]; | |||||
| } | |||||
| // Get single explain method chart data | |||||
| this.getSingalMethodChartData(); | |||||
| // Get single metric chart data | |||||
| this.getSingalMetricChartData(); | |||||
| }, | |||||
| /** | |||||
| * Get single explain method chart data | |||||
| */ | |||||
| getSingalMethodChartData() { | |||||
| const tempData = this.fullDict[this.multiMetricForm.selectedMethods]; | |||||
| const series = []; | |||||
| this.multiMetricForm.selectedMetrics.forEach((metric) => { | |||||
| const tempSerData = { | |||||
| name: metric, | |||||
| values: [], | |||||
| }; | |||||
| this.allLabels.forEach((label) => { | |||||
| if (tempData && tempData[label] && tempData[label][metric]) { | |||||
| tempSerData.values.push(tempData[label][metric]); | |||||
| } else { | |||||
| tempSerData.values.push(0); | |||||
| } | |||||
| }); | |||||
| series.push(tempSerData); | |||||
| }); | |||||
| this.multiMetricData = { | |||||
| legend: this.multiMetricForm.selectedMetrics, | |||||
| yAxis: this.allLabels, | |||||
| series: series, | |||||
| }; | |||||
| }, | |||||
| /** | |||||
| * Get single metric chart data | |||||
| */ | |||||
| getSingalMetricChartData() { | |||||
| const tempMetric = this.multiMethodForm.selectedMetrics; | |||||
| const series = []; | |||||
| this.multiMethodForm.selectedMethods.forEach((method) => { | |||||
| const tempData = this.fullDict[method]; | |||||
| const tempSerData = { | |||||
| name: method, | |||||
| values: [], | |||||
| }; | |||||
| this.allLabels.forEach((label) => { | |||||
| if (tempData && tempData[label] && tempData[label][tempMetric]) { | |||||
| tempSerData.values.push(tempData[label][tempMetric]); | |||||
| } else { | |||||
| tempSerData.values.push(0); | |||||
| } | |||||
| }); | |||||
| series.push(tempSerData); | |||||
| }); | |||||
| this.multiMethodData = { | |||||
| legend: this.multiMethodForm.selectedMethods, | |||||
| yAxis: this.allLabels, | |||||
| series: series, | |||||
| }; | |||||
| }, | |||||
| /** | |||||
| * Clear commmon data | |||||
| */ | |||||
| clearCllassifyCommonData() { | |||||
| this.fullDataDict = {}; | |||||
| this.classifyAllMethods = []; | |||||
| this.multiMetricForm = { | |||||
| selectedMethods: null, | |||||
| selectedMetrics: [], | |||||
| }; | |||||
| this.multiMetricData = { | |||||
| legend: [], | |||||
| yAxis: [], | |||||
| series: [], | |||||
| }; | |||||
| this.classifyAllMetrics = []; | |||||
| this.multiMethodForm = { | |||||
| selectedMethods: [], | |||||
| selectedMetrics: null, | |||||
| }; | |||||
| this.multiMethodData = { | |||||
| legend: [], | |||||
| yAxis: [], | |||||
| series: [], | |||||
| }; | |||||
| this.allLabels = []; | |||||
| }, | |||||
| /** | |||||
| * Callback of window size change | |||||
| */ | |||||
| resizeCallback() { | |||||
| if (this.resizeTimer) { | |||||
| clearTimeout(this.resizeTimer); | |||||
| this.resizeTimer = null; | |||||
| } | |||||
| this.resizeTimer = setTimeout(() => { | |||||
| this.resizeFlag = !this.resizeFlag; | |||||
| }, 500); | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss"> | |||||
| .cl-xai { | |||||
| height: 100%; | |||||
| background-color: #fff; | |||||
| padding: 0px 32px; | |||||
| padding-bottom: 32px; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| .cl-xai-title { | |||||
| height: 56px; | |||||
| line-height: 56px; | |||||
| display: flex; | |||||
| overflow: hidden; | |||||
| flex-direction: 0; | |||||
| .cl-xai-title-left { | |||||
| flex: 1; | |||||
| font-size: 20px; | |||||
| font-weight: bold; | |||||
| letter-spacing: -0.86px; | |||||
| i { | |||||
| color: #6c7280; | |||||
| margin-left: 12px; | |||||
| } | |||||
| } | |||||
| .cl-xai-title-right { | |||||
| flex: 1; | |||||
| text-align: right; | |||||
| .cl-close-btn { | |||||
| width: 20px; | |||||
| height: 20px; | |||||
| vertical-align: -3px; | |||||
| cursor: pointer; | |||||
| display: inline-block; | |||||
| line-height: 20px; | |||||
| margin-left: 32px; | |||||
| } | |||||
| } | |||||
| } | |||||
| .el-tabs__active-bar { | |||||
| width: 76px !important; | |||||
| } | |||||
| .el-tabs__item:nth-child(2) { | |||||
| margin-right: 10px !important; | |||||
| } | |||||
| .el-tabs__item:last-child { | |||||
| margin-left: 10px !important; | |||||
| } | |||||
| .is-active:nth-child(2) { | |||||
| margin-right: 10px !important; | |||||
| } | |||||
| .is-active:last-child { | |||||
| margin-left: 10px !important; | |||||
| } | |||||
| .el-tabs__active-bar { | |||||
| width: 0px !important; | |||||
| height: 0px !important; | |||||
| } | |||||
| .el-tabs__item { | |||||
| font-size: 14px; | |||||
| color: #303133; | |||||
| height: 40px !important; | |||||
| line-height: 36px !important; | |||||
| padding: 0px !important; | |||||
| span { | |||||
| font-weight: 500 !important; | |||||
| font-size: 14px; | |||||
| color: #303133; | |||||
| } | |||||
| span:hover { | |||||
| color: #00a5a7; | |||||
| i { | |||||
| color: #00a5a7; | |||||
| } | |||||
| } | |||||
| i { | |||||
| color: #6c7280; | |||||
| font-size: 14px; | |||||
| } | |||||
| } | |||||
| .el-tabs__item.is-active { | |||||
| color: #00a5a7; | |||||
| border-bottom: 2px solid #00a5a7; | |||||
| span { | |||||
| color: #00a5a7; | |||||
| font-weight: 700 !important; | |||||
| font-size: 14px; | |||||
| } | |||||
| i { | |||||
| color: #00a5a7; | |||||
| font-size: 14px; | |||||
| } | |||||
| } | |||||
| .el-tabs__header { | |||||
| margin: 0px; | |||||
| } | |||||
| .cl-xai-con { | |||||
| flex: 1; | |||||
| } | |||||
| .comprehensiveEvaluation { | |||||
| padding: 25px 0; | |||||
| .resultFalse { | |||||
| color: #f00 !important; | |||||
| } | |||||
| .firstColumn { | |||||
| color: #00a5a7; | |||||
| } | |||||
| .thTooltip { | |||||
| max-width: calc(100% - 25px); | |||||
| padding: 0px; | |||||
| vertical-align: middle; | |||||
| overflow: hidden; | |||||
| } | |||||
| .evaluation-table-header { | |||||
| th { | |||||
| background: #f5f7fa; | |||||
| } | |||||
| } | |||||
| } | |||||
| .image-noData { | |||||
| // Set the width and white on the right. | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| flex-direction: column; | |||||
| .noData-text { | |||||
| margin-top: 33px; | |||||
| font-size: 18px; | |||||
| } | |||||
| } | |||||
| .classify-container { | |||||
| height: 100%; | |||||
| .left-item { | |||||
| padding-right: 10px; | |||||
| } | |||||
| .right-itemm { | |||||
| padding-left: 10px; | |||||
| } | |||||
| .half-item { | |||||
| width: 50%; | |||||
| float: left; | |||||
| height: 100%; | |||||
| overflow: hidden; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| .operate-container { | |||||
| width: 100%; | |||||
| .container-name { | |||||
| font-size: 16px; | |||||
| font-weight: 700; | |||||
| padding: 15px 0px; | |||||
| } | |||||
| .select-see { | |||||
| padding-bottom: 10px; | |||||
| } | |||||
| .see-methods { | |||||
| font-size: 13px; | |||||
| // font-weight: bold; | |||||
| } | |||||
| .select-name { | |||||
| display: inline-block; | |||||
| padding-right: 10px; | |||||
| } | |||||
| } | |||||
| .chart-container { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| } | |||||
| .methods-show { | |||||
| padding: 10px 0px; | |||||
| .show-name { | |||||
| display: inline-block; | |||||
| margin-right: 10px; | |||||
| padding-bottom: 10px; | |||||
| } | |||||
| div { | |||||
| display: inline; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .classify { | |||||
| border-right: solid 1px #ddd; | |||||
| } | |||||
| .slectMethod { | |||||
| color: darkmagenta; | |||||
| } | |||||
| .el-select { | |||||
| height: 32px; | |||||
| width: 217px; | |||||
| } | |||||
| .el-input__inner { | |||||
| height: 32px; | |||||
| line-height: 32px; | |||||
| padding: 0px 15px; | |||||
| } | |||||
| } | |||||
| .el-tooltip__popper { | |||||
| .tooltip-container { | |||||
| .tooltip-style { | |||||
| .tooltip-title { | |||||
| font-size: 16px !important; | |||||
| font-weight: bold; | |||||
| color: #333333; | |||||
| } | |||||
| .tooltip-content { | |||||
| line-height: 20px; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> | |||||