How to use d3.symbols with an ordinal scale












2














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





























    2














    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



























      2












      2








      2







      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

      63.2k64384




      63.2k64384










      asked Nov 20 at 23:55









      Alex Lenail

      2,75742046




      2,75742046
























          1 Answer
          1






          active

          oldest

          votes


















          2














          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
            Nov 21 at 20:13











          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',
          autoActivateHeartbeat: false,
          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









          2














          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
            Nov 21 at 20:13
















          2














          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
            Nov 21 at 20:13














          2












          2








          2






          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

          63.2k64384




          63.2k64384












          • 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
            Nov 21 at 20:13


















          • 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
            Nov 21 at 20:13
















          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
          Nov 21 at 20:13




          Because it is indeed the area of the symbol. Unfortunately the API doesn't make it clear.
          – Gerardo Furtado
          Nov 21 at 20:13


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          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

          Tonle Sap (See)

          I get strange results when I access the Sqlitedatabase with Unity C# via XAMPP

          Guatemaltekische Davis-Cup-Mannschaft