How to use d3.symbols with an ordinal scale











up vote
1
down vote

favorite












TL;DR: How do I get a scaleOrdinal over the d3.symbols?



I'm hoping to use d3.symbols for an ordinal scale, corresponding to a categorical attribute on some data.




d3.symbols

An array containing the set of all built-in symbol types: circle, cross, diamond, square, star, triangle, and wye. Useful for constructing the range of an ordinal scale should you wish to use a shape encoding for categorical data.




Here's what I thought would work:






var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
var g = svg.append('g');

var data = [{type: 'a'}, {type: 'a'}, {type: 'a'}, {type: 'b'}, {type: 'b'}, {type: 'c'}];

var shape = d3.scaleOrdinal(d3.symbols);

var s = g.selectAll('.symbol').data(data);

/* Does not render */
s.enter()
.append('path')
.attr('d', d => shape(d.type))
.attr('x', (d, i) => i * 20)
.attr('y', 50);

/* Sanity Check: Properly renders */
s.enter()
.append('circle')
.attr('r',7)
.attr('cx', (d, i) => (i+1)*20)
.attr('cy', 100);

<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="graph-container"></div>





(alternately see fiddle).



Unfortunately the above fails with:



Error: <path> attribute d: Expected moveto path command ('M' or 'm'), "[object Object]".


Clearly shape(d.type) is not returning a valid path. It's actually returning an object with a single function named draw, i.e. it looks like { draw: function() { ... } }, which presumably refers to this draw method. Calling that draw method doesn't yield a valid path either, though, unfortunately.










share|improve this question




























    up vote
    1
    down vote

    favorite












    TL;DR: How do I get a scaleOrdinal over the d3.symbols?



    I'm hoping to use d3.symbols for an ordinal scale, corresponding to a categorical attribute on some data.




    d3.symbols

    An array containing the set of all built-in symbol types: circle, cross, diamond, square, star, triangle, and wye. Useful for constructing the range of an ordinal scale should you wish to use a shape encoding for categorical data.




    Here's what I thought would work:






    var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
    var g = svg.append('g');

    var data = [{type: 'a'}, {type: 'a'}, {type: 'a'}, {type: 'b'}, {type: 'b'}, {type: 'c'}];

    var shape = d3.scaleOrdinal(d3.symbols);

    var s = g.selectAll('.symbol').data(data);

    /* Does not render */
    s.enter()
    .append('path')
    .attr('d', d => shape(d.type))
    .attr('x', (d, i) => i * 20)
    .attr('y', 50);

    /* Sanity Check: Properly renders */
    s.enter()
    .append('circle')
    .attr('r',7)
    .attr('cx', (d, i) => (i+1)*20)
    .attr('cy', 100);

    <script src="https://d3js.org/d3.v5.min.js"></script>
    <div id="graph-container"></div>





    (alternately see fiddle).



    Unfortunately the above fails with:



    Error: <path> attribute d: Expected moveto path command ('M' or 'm'), "[object Object]".


    Clearly shape(d.type) is not returning a valid path. It's actually returning an object with a single function named draw, i.e. it looks like { draw: function() { ... } }, which presumably refers to this draw method. Calling that draw method doesn't yield a valid path either, though, unfortunately.










    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      TL;DR: How do I get a scaleOrdinal over the d3.symbols?



      I'm hoping to use d3.symbols for an ordinal scale, corresponding to a categorical attribute on some data.




      d3.symbols

      An array containing the set of all built-in symbol types: circle, cross, diamond, square, star, triangle, and wye. Useful for constructing the range of an ordinal scale should you wish to use a shape encoding for categorical data.




      Here's what I thought would work:






      var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
      var g = svg.append('g');

      var data = [{type: 'a'}, {type: 'a'}, {type: 'a'}, {type: 'b'}, {type: 'b'}, {type: 'c'}];

      var shape = d3.scaleOrdinal(d3.symbols);

      var s = g.selectAll('.symbol').data(data);

      /* Does not render */
      s.enter()
      .append('path')
      .attr('d', d => shape(d.type))
      .attr('x', (d, i) => i * 20)
      .attr('y', 50);

      /* Sanity Check: Properly renders */
      s.enter()
      .append('circle')
      .attr('r',7)
      .attr('cx', (d, i) => (i+1)*20)
      .attr('cy', 100);

      <script src="https://d3js.org/d3.v5.min.js"></script>
      <div id="graph-container"></div>





      (alternately see fiddle).



      Unfortunately the above fails with:



      Error: <path> attribute d: Expected moveto path command ('M' or 'm'), "[object Object]".


      Clearly shape(d.type) is not returning a valid path. It's actually returning an object with a single function named draw, i.e. it looks like { draw: function() { ... } }, which presumably refers to this draw method. Calling that draw method doesn't yield a valid path either, though, unfortunately.










      share|improve this question















      TL;DR: How do I get a scaleOrdinal over the d3.symbols?



      I'm hoping to use d3.symbols for an ordinal scale, corresponding to a categorical attribute on some data.




      d3.symbols

      An array containing the set of all built-in symbol types: circle, cross, diamond, square, star, triangle, and wye. Useful for constructing the range of an ordinal scale should you wish to use a shape encoding for categorical data.




      Here's what I thought would work:






      var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
      var g = svg.append('g');

      var data = [{type: 'a'}, {type: 'a'}, {type: 'a'}, {type: 'b'}, {type: 'b'}, {type: 'c'}];

      var shape = d3.scaleOrdinal(d3.symbols);

      var s = g.selectAll('.symbol').data(data);

      /* Does not render */
      s.enter()
      .append('path')
      .attr('d', d => shape(d.type))
      .attr('x', (d, i) => i * 20)
      .attr('y', 50);

      /* Sanity Check: Properly renders */
      s.enter()
      .append('circle')
      .attr('r',7)
      .attr('cx', (d, i) => (i+1)*20)
      .attr('cy', 100);

      <script src="https://d3js.org/d3.v5.min.js"></script>
      <div id="graph-container"></div>





      (alternately see fiddle).



      Unfortunately the above fails with:



      Error: <path> attribute d: Expected moveto path command ('M' or 'm'), "[object Object]".


      Clearly shape(d.type) is not returning a valid path. It's actually returning an object with a single function named draw, i.e. it looks like { draw: function() { ... } }, which presumably refers to this draw method. Calling that draw method doesn't yield a valid path either, though, unfortunately.






      var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
      var g = svg.append('g');

      var data = [{type: 'a'}, {type: 'a'}, {type: 'a'}, {type: 'b'}, {type: 'b'}, {type: 'c'}];

      var shape = d3.scaleOrdinal(d3.symbols);

      var s = g.selectAll('.symbol').data(data);

      /* Does not render */
      s.enter()
      .append('path')
      .attr('d', d => shape(d.type))
      .attr('x', (d, i) => i * 20)
      .attr('y', 50);

      /* Sanity Check: Properly renders */
      s.enter()
      .append('circle')
      .attr('r',7)
      .attr('cx', (d, i) => (i+1)*20)
      .attr('cy', 100);

      <script src="https://d3js.org/d3.v5.min.js"></script>
      <div id="graph-container"></div>





      var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
      var g = svg.append('g');

      var data = [{type: 'a'}, {type: 'a'}, {type: 'a'}, {type: 'b'}, {type: 'b'}, {type: 'c'}];

      var shape = d3.scaleOrdinal(d3.symbols);

      var s = g.selectAll('.symbol').data(data);

      /* Does not render */
      s.enter()
      .append('path')
      .attr('d', d => shape(d.type))
      .attr('x', (d, i) => i * 20)
      .attr('y', 50);

      /* Sanity Check: Properly renders */
      s.enter()
      .append('circle')
      .attr('r',7)
      .attr('cx', (d, i) => (i+1)*20)
      .attr('cy', 100);

      <script src="https://d3js.org/d3.v5.min.js"></script>
      <div id="graph-container"></div>






      javascript d3.js svg






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 21 at 0:18









      Gerardo Furtado

      62.8k64183




      62.8k64183










      asked Nov 20 at 23:55









      Alex Lenail

      2,65141845




      2,65141845
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          You're missing the symbol generator itself...



          var symbol = d3.symbol();


          ... to which you'll pass the type:



          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          //etc...


          Also, <path>s don't have x or y attributes.



          Here is the code with those changes:






          var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
          var g = svg.append('g');

          var data = [{
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'b'
          }, {
          type: 'b'
          }, {
          type: 'c'
          }];

          var shape = d3.scaleOrdinal(d3.symbols);

          var symbol = d3.symbol();

          var s = g.selectAll('.symbol').data(data);

          /* Does not render */
          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          .attr("transform", (_, i) => "translate(" + (20 + i * 20) + ",50)")
          .attr('fill', 'black');

          /* Properly renders */
          s.enter()
          .append('circle')
          .attr('r', 7)
          .attr('cx', (d, i) => (i + 1) * 20)
          .attr('cy', 100)
          .attr('fill', 'black');

          <div id="graph-container"></div>
          <script src="https://d3js.org/d3.v5.min.js"></script>








          share|improve this answer





















          • follow-up question: why do symbols.size() require such big sizes? What do those sizes refer to? There are hints that it might be the area of the symbol in the docs
            – Alex Lenail
            Nov 21 at 0:25










          • Because it is indeed the area of the symbol. Unfortunately the API doesn't make it clear.
            – Gerardo Furtado
            2 days ago











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53403371%2fhow-to-use-d3-symbols-with-an-ordinal-scale%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          2
          down vote



          accepted










          You're missing the symbol generator itself...



          var symbol = d3.symbol();


          ... to which you'll pass the type:



          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          //etc...


          Also, <path>s don't have x or y attributes.



          Here is the code with those changes:






          var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
          var g = svg.append('g');

          var data = [{
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'b'
          }, {
          type: 'b'
          }, {
          type: 'c'
          }];

          var shape = d3.scaleOrdinal(d3.symbols);

          var symbol = d3.symbol();

          var s = g.selectAll('.symbol').data(data);

          /* Does not render */
          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          .attr("transform", (_, i) => "translate(" + (20 + i * 20) + ",50)")
          .attr('fill', 'black');

          /* Properly renders */
          s.enter()
          .append('circle')
          .attr('r', 7)
          .attr('cx', (d, i) => (i + 1) * 20)
          .attr('cy', 100)
          .attr('fill', 'black');

          <div id="graph-container"></div>
          <script src="https://d3js.org/d3.v5.min.js"></script>








          share|improve this answer





















          • follow-up question: why do symbols.size() require such big sizes? What do those sizes refer to? There are hints that it might be the area of the symbol in the docs
            – Alex Lenail
            Nov 21 at 0:25










          • Because it is indeed the area of the symbol. Unfortunately the API doesn't make it clear.
            – Gerardo Furtado
            2 days ago















          up vote
          2
          down vote



          accepted










          You're missing the symbol generator itself...



          var symbol = d3.symbol();


          ... to which you'll pass the type:



          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          //etc...


          Also, <path>s don't have x or y attributes.



          Here is the code with those changes:






          var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
          var g = svg.append('g');

          var data = [{
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'b'
          }, {
          type: 'b'
          }, {
          type: 'c'
          }];

          var shape = d3.scaleOrdinal(d3.symbols);

          var symbol = d3.symbol();

          var s = g.selectAll('.symbol').data(data);

          /* Does not render */
          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          .attr("transform", (_, i) => "translate(" + (20 + i * 20) + ",50)")
          .attr('fill', 'black');

          /* Properly renders */
          s.enter()
          .append('circle')
          .attr('r', 7)
          .attr('cx', (d, i) => (i + 1) * 20)
          .attr('cy', 100)
          .attr('fill', 'black');

          <div id="graph-container"></div>
          <script src="https://d3js.org/d3.v5.min.js"></script>








          share|improve this answer





















          • follow-up question: why do symbols.size() require such big sizes? What do those sizes refer to? There are hints that it might be the area of the symbol in the docs
            – Alex Lenail
            Nov 21 at 0:25










          • Because it is indeed the area of the symbol. Unfortunately the API doesn't make it clear.
            – Gerardo Furtado
            2 days ago













          up vote
          2
          down vote



          accepted







          up vote
          2
          down vote



          accepted






          You're missing the symbol generator itself...



          var symbol = d3.symbol();


          ... to which you'll pass the type:



          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          //etc...


          Also, <path>s don't have x or y attributes.



          Here is the code with those changes:






          var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
          var g = svg.append('g');

          var data = [{
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'b'
          }, {
          type: 'b'
          }, {
          type: 'c'
          }];

          var shape = d3.scaleOrdinal(d3.symbols);

          var symbol = d3.symbol();

          var s = g.selectAll('.symbol').data(data);

          /* Does not render */
          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          .attr("transform", (_, i) => "translate(" + (20 + i * 20) + ",50)")
          .attr('fill', 'black');

          /* Properly renders */
          s.enter()
          .append('circle')
          .attr('r', 7)
          .attr('cx', (d, i) => (i + 1) * 20)
          .attr('cy', 100)
          .attr('fill', 'black');

          <div id="graph-container"></div>
          <script src="https://d3js.org/d3.v5.min.js"></script>








          share|improve this answer












          You're missing the symbol generator itself...



          var symbol = d3.symbol();


          ... to which you'll pass the type:



          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          //etc...


          Also, <path>s don't have x or y attributes.



          Here is the code with those changes:






          var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
          var g = svg.append('g');

          var data = [{
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'b'
          }, {
          type: 'b'
          }, {
          type: 'c'
          }];

          var shape = d3.scaleOrdinal(d3.symbols);

          var symbol = d3.symbol();

          var s = g.selectAll('.symbol').data(data);

          /* Does not render */
          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          .attr("transform", (_, i) => "translate(" + (20 + i * 20) + ",50)")
          .attr('fill', 'black');

          /* Properly renders */
          s.enter()
          .append('circle')
          .attr('r', 7)
          .attr('cx', (d, i) => (i + 1) * 20)
          .attr('cy', 100)
          .attr('fill', 'black');

          <div id="graph-container"></div>
          <script src="https://d3js.org/d3.v5.min.js"></script>








          var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
          var g = svg.append('g');

          var data = [{
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'b'
          }, {
          type: 'b'
          }, {
          type: 'c'
          }];

          var shape = d3.scaleOrdinal(d3.symbols);

          var symbol = d3.symbol();

          var s = g.selectAll('.symbol').data(data);

          /* Does not render */
          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          .attr("transform", (_, i) => "translate(" + (20 + i * 20) + ",50)")
          .attr('fill', 'black');

          /* Properly renders */
          s.enter()
          .append('circle')
          .attr('r', 7)
          .attr('cx', (d, i) => (i + 1) * 20)
          .attr('cy', 100)
          .attr('fill', 'black');

          <div id="graph-container"></div>
          <script src="https://d3js.org/d3.v5.min.js"></script>





          var svg = d3.select('#graph-container').append('svg').attr('xmlns', 'http://www.w3.org/2000/svg');
          var g = svg.append('g');

          var data = [{
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'a'
          }, {
          type: 'b'
          }, {
          type: 'b'
          }, {
          type: 'c'
          }];

          var shape = d3.scaleOrdinal(d3.symbols);

          var symbol = d3.symbol();

          var s = g.selectAll('.symbol').data(data);

          /* Does not render */
          s.enter()
          .append('path')
          .attr('d', d => symbol.type(shape(d.type))())
          .attr("transform", (_, i) => "translate(" + (20 + i * 20) + ",50)")
          .attr('fill', 'black');

          /* Properly renders */
          s.enter()
          .append('circle')
          .attr('r', 7)
          .attr('cx', (d, i) => (i + 1) * 20)
          .attr('cy', 100)
          .attr('fill', 'black');

          <div id="graph-container"></div>
          <script src="https://d3js.org/d3.v5.min.js"></script>






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 21 at 0:18









          Gerardo Furtado

          62.8k64183




          62.8k64183












          • follow-up question: why do symbols.size() require such big sizes? What do those sizes refer to? There are hints that it might be the area of the symbol in the docs
            – Alex Lenail
            Nov 21 at 0:25










          • Because it is indeed the area of the symbol. Unfortunately the API doesn't make it clear.
            – Gerardo Furtado
            2 days ago


















          • follow-up question: why do symbols.size() require such big sizes? What do those sizes refer to? There are hints that it might be the area of the symbol in the docs
            – Alex Lenail
            Nov 21 at 0:25










          • Because it is indeed the area of the symbol. Unfortunately the API doesn't make it clear.
            – Gerardo Furtado
            2 days ago
















          follow-up question: why do symbols.size() require such big sizes? What do those sizes refer to? There are hints that it might be the area of the symbol in the docs
          – Alex Lenail
          Nov 21 at 0:25




          follow-up question: why do symbols.size() require such big sizes? What do those sizes refer to? There are hints that it might be the area of the symbol in the docs
          – Alex Lenail
          Nov 21 at 0:25












          Because it is indeed the area of the symbol. Unfortunately the API doesn't make it clear.
          – Gerardo Furtado
          2 days ago




          Because it is indeed the area of the symbol. Unfortunately the API doesn't make it clear.
          – Gerardo Furtado
          2 days ago


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53403371%2fhow-to-use-d3-symbols-with-an-ordinal-scale%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Berounka

          Sphinx de Gizeh

          Different font size/position of beamer's navigation symbols template's content depending on regular/plain...