-2

I am trying to recreate this diagram in pure SVG (most preferred method), CSS, or through a Canvas (least preferred option). So far I can create 3 overlapping circles and add a value in the center of each. But when I go to add values to their intersecting parts I run into some troubles. I also do not know the logic to put text outside the venn diagram.

<svg width="500" height="500">
<circle cx="100" cy="100" r="80" fill="red" />
<circle cx="220" cy="100" r="80" fill="green" />
<circle cx="160" cy="180" r="80" fill="blue" />
<text x="100" y="100" dy=".3em" text-anchor="middle">A</text>
<text x="220" y="100" dy=".3em" text-anchor="middle">B</text>
<text x="160" y="180" dy=".3em" text-anchor="middle">C</text>
<path d="M 180,20 A 80,80 0 0,1 260,100 L 220,100 A 40,40 0 0,0 180,60 Z" fill="purple" />
<path d="M 140,100 A 80,80 0 0,1 180,60 L 140,60 A 40,40 0 0,0 100,100 Z" fill="orange" />
<path d="M 220,100 A 80,80 0 0,1 180,60 L 220,60 A 40,40 0 0,0 260,100 Z" fill="green" />
<text x="170" y="40" dy=".3em" text-anchor="middle">A ∩ C</text>
<text x="130" y="100" dy=".3em" text-anchor="middle">A ∩ B</text>
<text x="210" y="100" dy=".3em" text-anchor="middle">B ∩ C</text>
<text x="160" y="140" dy=".3em" text-anchor="middle">A ∩ B ∩ C</text>

enter image description here

adarian
  • 334
  • 7
  • 24
  • 2
    Please show what you have tried so far. It looks like the SVG should be a static image, so try to statically position the values above the intersections. Should the "outside" text be part of the SVG image, then you need to contain them in the [`viewBox`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox). – Oskar Grosser Mar 14 '23 at 00:58

1 Answers1

0

SVG image

Sidenote: SVG is XML-based; this is unlike HTML5. As such, SVG's attribute syntax requires quoted values, whereas in HTML5 unquoted attribute value syntax is allowed.
Browsers may occasionally fix this syntax error, but this caused me a headache in the past.

Always specify an SVG's namespace (xmlns="http://www.w3.org/2000/svg"). If you don't, the image may be recognized (and therefore rendered) incorrectly.

Also, always make sure to contain your graphics inside the visible region defined by the viewBox attribute. Anything outside the viewBox will be clipped and therefore invisible.

Venn diagram

The diagram appears to be static, so the elements can be positioned statically too. We won't have to worry about e.g. animations moving the elements outside the viewBox.

Simply position and colorize the <circle> and <text> elements within the viewBox.

I used <g> (group) elements to specify attributes that are inherited by default, to avoid duplicating the attributes on each element.

My SVG relies on some CSS to colorize the intersections. I chose this over more verbose alternatives:

<svg xmlns="http://www.w3.org/2000/svg"
    width="600" viewBox="-2 -2 4 4"
    style="background-color: white">
  <g fill-opacity=".6">
    <circle cx="-.5" cy=".577" r="1"
        fill="darkorange" style="mix-blend-mode:multiply" />
    <circle cx=".5" cy=".577" r="1"
        fill="darkturquoise" style="mix-blend-mode:multiply" />
    <circle cx="0" cy="-.33" r="1"
        fill="darkmagenta" style="mix-blend-mode:multiply" />
  </g>
  
  <g fill="white"
      font-size=".4" font-family="sans-serif"
      text-anchor="middle"
      dominant-baseline="hanging">
    <text y=".1">40</text>
    
    <text x="-1" y=".5">82</text>
    <text x="1" y=".5">88</text>
    <text y="-1">90</text>
    
    <text y=".8">58</text>
    <text x=".6" y="-.25">52</text>
    <text x="-.6" y="-.25">64</text>
  </g>
</svg>

Adding outside text

The labelling texts for the circles (i.e. "PR", "Ki67", "ER") need to be within the viewBox to be visible. In this case, the viewBox needs to be wider to contain them.

For the title (i.e. "% of Positivity") simply position it at the top left of the viewBox. You should also repeat its text in a <title> element to add an accessible name.

<svg xmlns="http://www.w3.org/2000/svg"
    width="600" viewBox="-2.5 -2 5 4"
    font-size=".4" font-family="sans-serif"
    style="background-color: white">
  <title>Percentage of Positivity</title>
  <text x="-2.5" y="-1.925"
      dominant-baseline="hanging"
      fill="gray">% of Positivity</text>

  <g fill-opacity=".6">
    <g fill="darkorange">
      <circle cx="-.5" cy=".577" r="1" style="mix-blend-mode:multiply" />
      <text x="-2.3" y=".5">PR</text>
    </g>
    <g fill="darkturquoise">
      <circle cx=".5" cy=".577" r="1" style="mix-blend-mode:multiply" />
      <text x="1.6" y="1.3">Ki67</text>
    </g>
    <g fill="darkmagenta">
      <circle cx="0" cy="-.33" r="1" style="mix-blend-mode:multiply" />
      <text x="1.2" y="-.5">ER</text>
    </g>
  </g>
  
  <g fill="white"
      text-anchor="middle"
      dominant-baseline="hanging">
    <text y=".1">40</text>
    
    <text x="-1" y=".5">82</text>
    <text x="1" y=".5">88</text>
    <text y="-1">90</text>
    
    <text y=".8">58</text>
    <text x=".6" y="-.25">52</text>
    <text x="-.6" y="-.25">64</text>
  </g>
</svg>

Note: I moved the text-related attributes font-family and font-size to a common ancestor (<svg>) to be inherited by the new <text> elements.


You can specify the SVG's preferred size with the width and height attributes. If one is specified, the other is set implicitly to match the aspect-ratio of the viewBox.

Embedding images in HTML

In HTML, you can embed SVG images directly, or as an external resource with the <img> element.

When embedded as an external resource, the browser only renders the SVG as an image. That means its content is translated into visual-only information, losing e.g. its texts and title.

As such, make sure to:

Example of embedding an SVG with an <img> element:

<img width="600" height="480"
    src="/percentage-of-positivity.svg"
    title="Percentage of Positivity"
    alt="82% in PR, 88% in Ki67, 90% in ER.
58% between PR and Ki67, 52% between Ki67 and ER, 64% between ER and PR.
40% between PR, Ki67 and ER.">

You may want to be conscious about your use of white-space in the alt attribute, in case you want to preserve it (see CSS white-space property).

To add a caption for the image, use the <figcaption> element:

/*<figure> and <figcaption> can also be styled!*/
figure {
  border: 1px solid lightgray;
  border-radius: .2rem;
  padding: .4rem;
}
figcaption:first-child {margin-block-end: .4rem}
figcaption:last-child {margin-block-start: .4rem}
figure>:not(figcaption) {background-color: #eee}

img[alt] {white-space:pre-line}
<figure>
  <img src="/percentage-of-positivity.svg"
      title="Percentage of Posivity"
      alt="82% in PR, 88% in Ki67, 90% in ER.
58% between PR and Ki67, 52% between Ki67 and ER, 64% between ER and PR.
40% between PR, Ki67 and ER.">
  <figcaption>Percentage of positivity in PR, ER and Ki67 shown in a Venn diagram</figcaption>
</figure>

Note: Titles and captions are not the same! Think of a title as a short name, and of a caption as a short description.

Oskar Grosser
  • 2,804
  • 1
  • 7
  • 18
  • Perfect thank you. Not sure why the question is closed/flagged when this answer solves the problem. – adarian Mar 14 '23 at 08:38