block by michalskop 7e55931562cb3e5a9344

Hemicycle chart (general)

Full Screen

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <!--<script src="d3.v3.js"></script>-->
    <script src="//d3js.org/d3.v3.min.js"></script>
    <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"> <!-- note: //stackoverflow.com/questions/20032426/fontawesome-doesnt-display-in-firefox -->
    <link href="//maxcdn.bootstrapcdn.com/bootswatch/3.2.0/united/bootstrap.min.css" rel="stylesheet">
    <style>
    
    .axis path,
      .axis line {
          fill: none;
          stroke: #000;
          shape-rendering: crispEdges;
        }
          path, line {
        stroke:#bbb;
        stroke-width:1
      }
      /*//www.d3noob.org/2013/01/adding-drop-shadow-to-allow-text-to.html*/
      text.shadow {
        stroke: gray;
        stroke-width: 1px;
        opacity: 0.9;
    }
    .half {
      fill: #888;
      opacity:0.5;
    }
        </style>
  </head>
  <body>
    <div class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <span class="navbar-brand">Hemicycle - for parliaments/councils of any size, with draggable majority arc</span>
        </div>
      </div>
    </div>
    <div id="chart"></div>
    <div class="alert alert-info">
      The <strong>algorithm.py</strong> calculates optimal number of representatives in each row for several numbers of rows (+ size of icons and gap between the rows). These numbers are used as parameters for the chart.
      <br/><em>It may be slow for big parliaments, but it is needed just once for any number (e.g., 200 representatives took about 1 hour, due to the grid search - further optimization possible, my trial using steepest descent algorithm did not converge many times).</em>
    </div>
    <div class="col-lg-4">
      <div class="bs-component">
        <div class="list-group">
          <a href="#" class="list-group-item active">Legend</a>
          <a href="#" class="list-group-item">
            <div id="legend"></div>
          </a>
        </div>
      </div>
      <div class="alert alert-info">
      The legend is also created as a svg picture.
      </div>
    </div>
    <script>

    // 2:1!
var margin = {top: 0, right: 0, bottom: 0, left: 0},
    width = 600 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;

var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

/*examples of parliaments*/
/*Plasy 2010*/
/*var groups = [
  {'name':'KSČM','n':2,'color':'red'},
  {'name':'ČSSD','n':4,'color':'orange'},
  {'name':'KDU-ČSL','n':2,'color':'yellow'},
  {'name':'TOP 09','n':2,'color':'violet'},
  {'name':'ODS','n':5,'color':'blue'}
];*/
/*Czech Republic 2013*/
var groups = [
  {'name':'KSČM','n':33,'color':'red'},
  {'name':'Úsvit','n':14,'color':'pink'},
  {'name':'ČSSD','n':50,'color':'orange'},
  {'name':'KDU-ČSL','n':14,'color':'yellow'},
  {'name':'ANO','n':47,'color':'aqua'},
  {'name':'TOP 09','n':26,'color':'purple'},
  {'name':'ODS','n':16,'color':'blue'}
];
/*Czech Republic Senate 2013*/
/*var groups = [
  {'name':'KSČM','n':2,'color':'red'}, 
  {'name':'ČSSD','n':46,'color':'orange'},
  {'name':'SPOZ','n':1,'color':'pink'},
  {'name':'Severočeši','n':2,'color':'darkred'},
  {'name':'Piráti','n':1,'color':'black'},
  {'name':'Zelení','n':1,'color':'green'},
  {'name':'KDU-ČSL','n':5,'color':'yellow'},
  {'name':'Nezávislí kand.','n':1,'color':'gray'},
  {'name':'Nestraníci','n':1,'color':'aqua'},
  {'name':'TOP 09 + STAN','n':4,'color':'purple'},
  {'name':'Ostravak','n':1,'color':'brown'},
  {'name':'ODS','n':15,'color':'blue'},
  {'name':'Neobsazeno','n':1,'color':'white'}
];*/

/*European Parliament 2014*/
/*var groups = [
  {'name':'GUE-NGL','n':52,'color':'darkred'},
  {'name':'Greens-EFA','n':50,'color':'green'},
  {'name':'S&D','n':191,'color':'red'},
  {'name':'ALDE','n':67,'color':'yellow'},
  {'name':'EPP','n':221,'color':'blue'},
  {'name':'ECR','n':70,'color':'darkblue'},
  {'name':'EFDD','n':48,'color':'aqua'},
  {'name':'Non-inscrits','n':52,'color':'gray'}
];*/

/*Plasy*/
/*var h = {
  'n': [6,9],
  'g': 1.19,
  'w': 0.52,
}*/

/*CZ*/
/*var h = {
  'n': [33,37,40,43,47],
  'g': 1.17,
  'w': 0.09,
}
var h = {
  'n': [24,28,31,35,39,43],
  'g': 1.23,
  'w': 0.13,
}
var h = {
  'n': [18,21,25,29,32,36,39],
  'g': 1.19,
  'w': 0.17,
}*/
var h = {
  'n': [8,11,15,19,22,26,29,33,37],
  'g': 1.20,
  'w': 0.39,
}
/*var h = {
  'n': [4,8,11,15,18,22,25,29,32,36],
  'g': 1.20,
  'w': 0.73,
}*/

/*CZ Senate*/
/*var h = {
  'n': [9,13,16,20,23],
  'g': 1.2,
  'w': 0.34,
}*/
/*EP*/
/*var h = {
  'n': [85,88,90,93,95,98,100,102],
  'g': 1.16,
  'w': 0.03,
}
var h = {
  'n': [31,34,38,41,45,48,52,55,59,62,66,69,73,78],
  'g': 1.19,
  'w': 0.1,
}*/

//max radius (for scales)
rmax = 1 + h['n'].length *h['g']*h['w'];

var 
	xScale = d3.scale.linear()
	  .domain([-1*rmax, rmax])
	  .range([0, width]),
    yScale = d3.scale.linear()
      .domain([0, rmax])
      .range([height,0])
    x0Scale = d3.scale.linear()
	  .domain([0, 2*rmax])
	  .range([0, width]);

//generate data: 1 representative ~ 1 datum
data = [];
s = [];
for (i in h['n']) {
  s.push((Math.PI/h['w'] + Math.PI*i*h['g']-h['n'][i])/(h['n'][i] - 1));
  ninrow = h['n'][i];
  radwidth = Math.PI/(h['n'][i]+(h['n'][i]-1)*s[i]);
  radspace = radwidth*s[i];
  r = 1 + i*h['g']*h['w'];
  for (j=0;j<ninrow;j++) {
    x = Math.cos(radwidth*(0.5+j)+j*radspace)*r;
    y = Math.sin(radwidth*(0.5+j)+j*radspace)*r;
    rot = -1*(radwidth*(0.5+j)+j*radspace)/Math.PI*180+90;
    data.push({'x':x,'y':y,'rot':rot});
  }
}

//sort data by rotation (representatives from 1 parl. groups together)
data.sort(function(x,y) {
  if (x['rot'] < y['rot']) return -1;
  if (x['rot'] > y['rot']) return 1;
  return 0
});

//add colors and names to data - may be used later
i = 0;
for (gkey in groups) {
  group = groups[gkey];
  for (j=0;j<group['n'];j++) {
    data[i]['color'] = group['color'];
    data[i]['name'] = group['name'];
    i++;
  }
}

/* MAJORITY ARC */
var angle = [{'startangle':0,'endangle':Math.PI/2}];

var arci = d3.svg.arc()
                .startAngle(function(d){return d.startangle})
                .endAngle(function(d){return d.endangle})
                .outerRadius(x0Scale(rmax))
                .innerRadius(0);

var position = [xScale(0),yScale(0)];
             
////stackoverflow.com/questions/8538651/d3-update-data-and-update-graph             
var arc = svg.selectAll('.half') 
    .data(angle)
    .enter()
    .append("path")
    .attr("d",arci)
    .attr("transform", "translate(" + position + ")")
    .attr("class","half");

////stackoverflow.com/questions/15303342/how-to-apply-drag-behavior-to-a-d3-svg-arc
var drag = d3.behavior.drag()
    .on("drag", function(d,i) {
        alpha1 = Math.atan((d3.event.x - xScale(0))/(-d3.event.y + yScale(0)));
        x2 = d3.event.dx + d3.event.x;
        y2 = d3.event.dy + d3.event.y;
        alpha2 = Math.atan((x2 - xScale(0))/(-y2 + yScale(0)));
        alpha = alpha2-alpha1;
        angle[0]['startangle'] += alpha;
        angle[0]['endangle'] += alpha;
        /*angle[0]['startangle'] = Math.min(0,angle[0]['startangle']);
        angle[0]['startangle'] = Math.max(Math.PI/2,angle[0]['startangle']);
        angle[0]['endangle'] = Math.min(Math.PI/2,angle[0]['endangle']);
        angle[0]['endangle'] = Math.max(Math.PI,angle[0]['endangle']);*/
        arc.attr("d",arci);   // redraw the arc
        /*position[0] += d3.event.dx;
        position[1] += d3.event.dy;
        d3.select(this)
        .attr("transform", function(d,i){
            return "translate(" + position + ")"
        })*/
    });
arc.call(drag);

// creating HEMICYCLE
var icons = svg.selectAll(".icon")
		.data(data)
      .enter().append("text")
        .attr('font-family', 'FontAwesome')
        .attr('font-size',x0Scale(h['w']*1.15)) //the icon is about 1.15times higher then wide
        .attr('fill', function(d) {return d.color;})
        .attr('text-anchor',"middle")
        .attr('class', 'shadow')
        .attr('x',function(d) {return xScale(d.x);})
        .attr('y',function(d) {return yScale(d.y);})
        .attr("transform",function(d) {return "rotate("+d.rot+","+xScale(d.x)+","+yScale(d.y)+")"})
        .text('\uf007');

//custom text
svg.append("text")
  .attr('font-family', 'sans-serif')
  .attr('font-size',x0Scale(h['w']*1))        //adjust as needed
  .attr('font-weight','bold')
  .attr('text-anchor',"middle")
  .attr('fill', '#444')
  .attr('x',xScale(0)) 
  .attr('y',yScale(0))
  .text("CZ 2013");

/* LEGEND */
heightleg = x0Scale(groups.length * h['w']*1.15*h['g']);
var svgleg = d3.select("#legend").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", heightleg + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//sorting for legend
groups.sort(function(x,y) {
  if (x.n > y.n) return -1;
  if (x.n < y.n) return 1;
  return 0;
});
//creating legend
var iconsleg = svgleg.selectAll(".iconleg")
		.data(groups)
      .enter().append("text")
        .attr('font-family', 'FontAwesome')
        .attr('font-size',x0Scale(h['w']*1.15))
        .attr('fill', function(d) {return d.color;})
        .attr('text-anchor',"middle")
        .attr('class', 'shadow')
        .attr('x',x0Scale(h['w']*1.15))
        .attr('y',function(d,i) {return (i+1)*x0Scale(h['w']*1.15);})
        .text('\uf007');

var textleg = svgleg.selectAll(".textleg")
		.data(groups)
      .enter().append("text")
        .attr('font-family', 'sans-serif')
        .attr('font-size',x0Scale(h['w']*0.9))
        //.attr('fill', function(d) {return d.color;})
        //.attr('text-anchor',"middle")
        //.attr('class', 'shadow')
        .attr('x',x0Scale(2*h['w']*1.15))
        .attr('y',function(d,i) {return (i+1)*x0Scale(h['w']*1.15);})
        .text(function(d){return d.name + ' (' + d.n + ')'});
   </script>
  </body>
</html>

algorithm.py


# calculates optimal numbers of representives for hemicycle chart
import math
import csv
import numpy as np
import timeit

start = timeit.default_timer()
#benchmark:
#n0 = 200 : 4:23s, 5:52s, 6:132s, 7:285s, 8:579s, 9:1167s , 10:2342s, 11: 4632s
#n0=751 : 7:217s, 8:570s, 9:1331, 10:2816s, 11: 5686s, 12: 10905s, 13:21918s,14:44362s


# number of representatives
n0=751


optim = {}

# loss function 1 (gaps between rows)
def loss1(g):
  return (g-1.2)*(g-1.2) #looks best

# loss function 2 (spaces in rows)
def loss2(w,s,n):
  n0 = sum(n)
  l2 = 0
  i = 0
  ln = len(n)
  for item in n:
    if s[i] > 0:
      #l2 = l2 + item*(s[i] - 0.1*w)*(s[i] - 0.1*w)/n0
      l2 = l2 + (s[i] - 0.1*w)*(s[i] - 0.1*w)/ln
    else:
      l2 = l2 + 10
    i = i + 1
  return l2

# loss function
def lossf(w,g,s,n):
  l1 = loss1(g)
  l2 = loss2(w,s,n)
  l = l1 + l2 + (l1 - l2)*(l1 - l2)
  return l

# spaces in rows
def ss(w,g,n):
  s = [0]*len(n)
  i = 0
  for item in n:
    s[i] = (math.pi/w + math.pi*i*g-n[i])/(n[i] - 1)
    i = i + 1 
  return s

# max n in row for grid search
def nmax(k,n):
  return math.floor(n-((k-1)*k/2))/k

# nrow for grid search
def nrow(n):
  return {'max':round(math.sqrt(n)*3/4),'min':round(max(math.sqrt(n)/4,1))}

# grid search
def grid(n):
  out = []
  for k in np.arange (0.01,1,0.01): #(0.01,1,0.005):
    for kk in np.arange (1.15,1.25,0.01): #(1,1.35,0.01)
      g = kk
      w = k
      s = ss(w,g,n)
      l1 = loss1(g)
      l2 = loss2(w,s,n)
      l = l1 + l2 + (l1-l2)*(l1-l2)
      try:
        if l < mmin:
          out = [w,g]
          mmin = l
      except:
        out = [w,g]
        mmin = l
  #print(out,mmin)
  return {'w':out[0],'g':out[1],'loss':mmin}     
    #outwriter.writerow(row)

# recursion
def go(level,n,nrows,n0):
#  print(n,level)
  global optim
#  print('optim:',optim)
  global ll
  while level < (nrows-1):
    #conservative (slow):
#    jmin = max(level+2,n[level-1]+1)
#    jmax = int(nmax(nrows-level,n0-sum(n[0:level]))+1)
    #faster (aritmetic series):
    if level > 0:
      if (nrows>1):
        q = 2*(n0-nrows*n[0])/(nrows-1)/nrows
        jmin = math.floor(n[0] + level*q - 0.5) #better with  -1, but slower
        jmax = math.ceil(n[0] + level*q + 0.5) #better with  +1, but slower
      else:
        jmin = max(level+2+round(sqrt(level)),n[level-1]+1)
        jmax = int(nmax(nrows-level,n0-sum(n[0:level]))+1)
    else:
      jmin = max(level+2,n[level-1]+1)
      jmax = int(nmax(nrows-level,n0-sum(n[0:level]))+1)
    for j in range(jmin,jmax):
      n[level] = j
      go(level+1,n,nrows,n0)
    return False
  n[level] = n0-sum(n)
#  print("calculating:",level,k,n)
  opt = grid(n)
#  print(opt,ll)
  try:
    if ll > opt['loss']:
      optim = opt.copy()
      optim['n'] = n.copy()
      ll = optim['loss']
  except:
    optim = opt.copy()
    optim['n'] = n.copy()
    ll = optim['loss']
#  print('optim2:',optim)
  n[level] = 0
  return True

# for each reasonable number of rows:
nr = nrow(n0)
for k in range(nr['min'],nr['max']+1):
  n = [0]*k
  optim = {}
  ll = 100000000
  go(0,n,k,n0)
  print("final optim:",optim)
  print("time:",timeit.default_timer() - start)


    
#example of results:
#n = 200:
#final optim: {'n': [44, 48, 52, 56], 'loss': 6.0494609377272378e-05, 'w': 0.069999999999999993, 'g': 1.2000000000000002}
#time: 23.457229251012905
#final optim: {'n': [34, 37, 40, 43, 46], 'loss': 0.003021820005212728, 'w': 0.089999999999999997, 'g': 1.1900000000000002}
#time: 51.52483937999932
#final optim: {'n': [24, 28, 31, 35, 39, 43], 'loss': 0.0009935459225664401, 'w': 0.13, 'g': 1.2300000000000002}
#time: 131.58585535301245
#final optim: {'n': [18, 21, 25, 29, 32, 36, 39], 'loss': 0.000796945129917957, 'w': 0.17000000000000001, 'g': 1.1900000000000002}
#time: 284.771323367022
#final optim: {'n': [12, 16, 19, 23, 27, 31, 34, 38], 'loss': 0.00031275649495655434, 'w': 0.25, 'g': 1.2000000000000002}
#time: 579.2367971060157
#final optim: {'n': [8, 11, 15, 19, 22, 26, 29, 33, 37], 'loss': 0.00043985954926300044, 'w': 0.39000000000000001, 'g': 1.2000000000000002}
#time: 1167.0518377900007
#final optim: {'n': [4, 8, 11, 15, 18, 22, 25, 29, 32, 36], 'loss': 0.00064177079858304589, 'w': 0.72999999999999998, 'g': 1.2000000000000002}
#time: 2341.9838014570123
#final optim: {'n': [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 35], 'loss': 0.0087001372112743003, 'w': 0.98999999999999999, 'g': 1.1400000000000001}
#time: 4631.68083341801


#n = 751 (Euro Parliament)
#final optim: {'n': [98, 101, 104, 107, 110, 113, 118], 'loss': 0.0062929076050250469, 'w': 0.029999999999999999, 'g': 1.1899999999999999}
#time: 217.3275479080039
#final optim: {'n': [85, 88, 90, 93, 95, 98, 100, 102], 'loss': 0.068194024500854655, 'w': 0.029999999999999999, 'g': 1.1599999999999999}
#time: 570.2674658489996
#final optim: {'n': [71, 74, 77, 80, 83, 87, 90, 93, 96], 'loss': 0.014035298736485213, 'w': 0.040000000000000001, 'g': 1.1799999999999999}
#time: 1331.067573258013
#final optim: {'n': [60, 63, 67, 70, 73, 77, 80, 83, 87, 91], 'loss': 0.0032756194901112823, 'w': 0.050000000000000003, 'g': 1.1899999999999999}
#time: 2816.806992516009
#final optim: {'n': [51, 54, 58, 61, 65, 68, 72, 75, 79, 82, 86], 'loss': 0.0013354982259395371, 'w': 0.060000000000000005, 'g': 1.1899999999999999}
#time: 5686.576568382996
#final optim: {'n': [44, 47, 51, 54, 57, 61, 64, 68, 71, 74, 78, 82], 'loss': 0.0016497989012379932, 'w': 0.069999999999999993, 'g': 1.1899999999999999}
#time: 10905.816249452997
#final optim: {'n': [34, 38, 42, 46, 50, 54, 58, 62, 66, 70, 73, 77, 81], 'loss': 0.0025690587369525267, 'w': 0.089999999999999997, 'g': 1.25}
#time: 21918.771677729994
#final optim: {'n': [31, 34, 38, 41, 45, 48, 52, 55, 59, 62, 66, 69, 73, 78], 'loss': 0.00099189844185821208, 'w': 0.099999999999999992, 'g': 1.1899999999999999}
#time: 44362.27788667599
# ...

# n = 81 (CZ Senate)
#final optim: {'n': [39, 42], 'loss': 0.00015113520955957024, 'w': 0.080000000000000002, 'g': 1.2}
#time: 2.056351581995841
#final optim: {'n': [23, 27, 31], 'loss': 0.00074731223308436374, 'w': 0.13, 'g': 1.2}
#time: 3.672953786997823
#final optim: {'n': [15, 18, 22, 26], 'loss': 0.0017986444368775138, 'w': 0.20000000000000001, 'g': 1.1899999999999999}
#time: 5.949895355995977
#final optim: {'n': [9, 13, 16, 20, 23], 'loss': 0.0004283781313137963, 'w': 0.34000000000000002, 'g': 1.2}
#time: 10.962005101988325
#final optim: {'n': [5, 8, 12, 15, 19, 22], 'loss': 0.0011676166427925727, 'w': 0.62, 'g': 1.1899999999999999}
#time: 21.31037131600897
#final optim: {'n': [3, 6, 9, 12, 14, 17, 20], 'loss': 0.017012374030482232, 'w': 0.98999999999999999, 'g': 1.1499999999999999}
#time: 41.0609374709893

legend.svg

<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="600" height="216.84957789716043" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"><![CDATA[
.axis path, .axis line { fill: none; stroke: rgb(0, 0, 0); shape-rendering: crispedges; }
path, line { stroke: rgb(187, 187, 187); stroke-width: 1px; }
text.shadow { stroke: rgb(128, 128, 128); stroke-width: 1px; opacity: 0.9; }
.half { fill: rgb(136, 136, 136); opacity: 0.5; }]]></style></defs><g transform="translate(0,0)"><text font-family="FontAwesome" font-size="25.81542594013814" fill="orange" text-anchor="middle" class="shadow" x="25.81542594013814" y="25.81542594013814"></text><text font-family="FontAwesome" font-size="25.81542594013814" fill="aqua" text-anchor="middle" class="shadow" x="25.81542594013814" y="51.63085188027628"></text><text font-family="FontAwesome" font-size="25.81542594013814" fill="red" text-anchor="middle" class="shadow" x="25.81542594013814" y="77.44627782041442"></text><text font-family="FontAwesome" font-size="25.81542594013814" fill="purple" text-anchor="middle" class="shadow" x="25.81542594013814" y="103.26170376055256"></text><text font-family="FontAwesome" font-size="25.81542594013814" fill="blue" text-anchor="middle" class="shadow" x="25.81542594013814" y="129.0771297006907"></text><text font-family="FontAwesome" font-size="25.81542594013814" fill="pink" text-anchor="middle" class="shadow" x="25.81542594013814" y="154.89255564082885"></text><text font-family="FontAwesome" font-size="25.81542594013814" fill="yellow" text-anchor="middle" class="shadow" x="25.81542594013814" y="180.707981580967"></text><text font-family="sans-serif" font-size="20.20337682271681" x="51.63085188027628" y="25.81542594013814">ČSSD (50)</text><text font-family="sans-serif" font-size="20.20337682271681" x="51.63085188027628" y="51.63085188027628">ANO (47)</text><text font-family="sans-serif" font-size="20.20337682271681" x="51.63085188027628" y="77.44627782041442">KSČM (33)</text><text font-family="sans-serif" font-size="20.20337682271681" x="51.63085188027628" y="103.26170376055256">TOP 09 (26)</text><text font-family="sans-serif" font-size="20.20337682271681" x="51.63085188027628" y="129.0771297006907">ODS (16)</text><text font-family="sans-serif" font-size="20.20337682271681" x="51.63085188027628" y="154.89255564082885">Úsvit (14)</text><text font-family="sans-serif" font-size="20.20337682271681" x="51.63085188027628" y="180.707981580967">KDU-ČSL (14)</text></g></svg>

plasy.svg

<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="600" height="300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"><![CDATA[
.axis path, .axis line { fill: none; stroke: rgb(0, 0, 0); shape-rendering: crispedges; }
path, line { stroke: rgb(187, 187, 187); stroke-width: 1px; }
text.shadow { stroke: rgb(128, 128, 128); stroke-width: 1px; opacity: 0.9; }
.half { fill: rgb(136, 136, 136); opacity: 0.5; }]]></style></defs><g transform="translate(0,0)"><path d="M-270.02845244780104,-130.70820505479136A300,300 0 0,1 130.70820505479136,-270.02845244780104L0,0Z" transform="translate(300,300)" class="half"></path><text font-family="FontAwesome" font-size="80.17518770110831" fill="red" text-anchor="middle" class="shadow" x="85.75726010756388" y="265.29090179034534" transform="rotate(-80.7975644468734,85.75726010756388,265.29090179034534)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="red" text-anchor="middle" class="shadow" x="170.43395001771813" y="265.532639628331" transform="rotate(-75.1030973265986,170.43395001771813,265.532639628331)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="orange" text-anchor="middle" class="shadow" x="110.91854020735812" y="193.45013065315834" transform="rotate(-60.598173335154996,110.91854020735812,193.45013065315834)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="orange" text-anchor="middle" class="shadow" x="205.09432635105534" y="205.2990319572094" transform="rotate(-45.06185839595915,205.09432635105534,205.2990319572094)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="orange" text-anchor="middle" class="shadow" x="159.33809073878794" y="134.71569833122072" transform="rotate(-40.39878222343668,159.33809073878794,134.71569833122072)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="orange" text-anchor="middle" class="shadow" x="225.05998666471191" y="96.31232856048376" transform="rotate(-20.19939111171834,225.05998666471191,96.31232856048376)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="yellow" text-anchor="middle" class="shadow" x="265.2529527130464" y="170.50867618315183" transform="rotate(-15.02061946531974,265.2529527130464,170.50867618315183)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="yellow" text-anchor="middle" class="shadow" x="300" y="82.96388988201645" transform="rotate(0,300,82.96388988201645)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="violet" text-anchor="middle" class="shadow" x="334.74704728695355" y="170.50867618315183" transform="rotate(15.020619465319712,334.74704728695355,170.50867618315183)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="violet" text-anchor="middle" class="shadow" x="374.94001333528803" y="96.31232856048376" transform="rotate(20.19939111171834,374.94001333528803,96.31232856048376)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="blue" text-anchor="middle" class="shadow" x="440.66190926121214" y="134.71569833122084" transform="rotate(40.39878222343669,440.66190926121214,134.71569833122084)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="blue" text-anchor="middle" class="shadow" x="394.9056736489447" y="205.2990319572094" transform="rotate(45.061858395959156,394.9056736489447,205.2990319572094)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="blue" text-anchor="middle" class="shadow" x="489.08145979264185" y="193.4501306531584" transform="rotate(60.598173335155025,489.08145979264185,193.4501306531584)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="blue" text-anchor="middle" class="shadow" x="429.5660499822818" y="265.532639628331" transform="rotate(75.1030973265986,429.5660499822818,265.532639628331)"></text><text font-family="FontAwesome" font-size="80.17518770110831" fill="blue" text-anchor="middle" class="shadow" x="514.242739892436" y="265.2909017903453" transform="rotate(80.79756444687337,514.242739892436,265.2909017903453)"></text><text font-family="sans-serif" font-size="31.372899535216302" font-weight="bold" text-anchor="middle" fill="#444" x="300" y="300">PLASY '10-'14</text></g></svg>