amcharts / amcharts5

The newest, fastest, and most advanced amCharts charting library for JavaScript and TypeScript apps.
Other
345 stars 92 forks source link

Question: V5 JSON Config to hide PieChart slices label and use circles as legend marker #1689

Closed flaming-cl closed 1 week ago

flaming-cl commented 1 month ago

Question Hey, if we would like to hide the slice labels (like France:29.4%), and make the square legend to be circle legend, how to implement it with amcharts 5 JSON config?

Screenshot 2024-08-28 at 4 39 53 PM

Ideal effect for us:

  1. without slice label:

    Screenshot 2024-08-28 at 4 45 30 PM
  2. circle legend:

    Screenshot 2024-08-28 at 4 44 23 PM

Current Code

am5plugins_json.JsonParser.new(root)
    .parse(
      {
        refs: [
          {
            data: [
              {
                country: 'France',
                sales: 100000
              },
              {
                country: 'Spain',
                sales: 160000
              },
              {
                country: 'United Kingdom',
                sales: 80000
              }
            ]
          },
          {
            series: {
              type: 'PieSeries',
              settings: {
                name: 'Series',
                valueField: 'sales',
                innerRadius: {
                  type: 'Percent',
                  value: 82
                },
                radius: {
                  type: 'Percent',
                  value: 100
                },
                width: {
                  type: 'Percent',
                  value: 100
                },
                categoryField: 'country'
              },
              properties: {
                data: '#data'
              }
            }
          }
        ],
        type: 'PieChart',
        settings: {
          layout: 'horizontal'
        },
        properties: {
          series: ['#series']
        },
        children: [
          {
            type: 'Label',
            settings: {
              text: '[#5a5a5a]Total Rates[/]',
              fontSize: 18,
              fontWeight: '500',
              textAlign: 'center',
              x: {
                type: 'Percent',
                value: 25
              },
              y: {
                type: 'Percent',
                value: 20
              },
              centerX: {
                type: 'Percent',
                value: 50
              },
              paddingTop: 0,
              paddingBottom: 0
            }
          },
          {
            type: 'Legend',
            settings: {
              centerX: {
                type: 'Percent',
                value: 50
              },
              x: {
                type: 'Percent',
                value: 70
              },
              centerY: {
                type: 'Percent',
                value: 50
              },
              y: {
                type: 'Percent',
                value: 50
              },
              layout: 'vertical',
              marker: 'circle'
            },
            properties: {
              data: '#series.dataItems'
            }
          }
        ]
      },
      {
        parent: root.container
      }
    )

Environment (if applicable)

Additional context

martynasma commented 1 month ago

Here you go:

am5plugins_json.JsonParser.new(root).parse(
  {
    refs: [
      {
        data: [
          {
            country: "France",
            sales: 100000
          },
          {
            country: "Spain",
            sales: 160000
          },
          {
            country: "United Kingdom",
            sales: 80000
          }
        ]
      },
      {
        series: {
          type: "PieSeries",
          settings: {
            name: "Series",
            valueField: "sales",
            innerRadius: {
              type: "Percent",
              value: 82
            },
            radius: {
              type: "Percent",
              value: 100
            },
            width: {
              type: "Percent",
              value: 100
            },
            categoryField: "country"
          },
          properties: {
            data: "#data",
            labels: {
              properties: {
                template: {
                  settings: {
                    forceHidden: true
                  }
                }
              }
            },
            ticks: {
              properties: {
                template: {
                  settings: {
                    forceHidden: true
                  }
                }
              }
            }
          }
        }
      }
    ],
    type: "PieChart",
    settings: {
      layout: "horizontal"
    },
    properties: {
      series: ["#series"]
    },
    children: [
      {
        type: "Label",
        settings: {
          text: "[#5a5a5a]Total Rates[/]",
          fontSize: 18,
          fontWeight: "500",
          textAlign: "center",
          x: {
            type: "Percent",
            value: 25
          },
          y: {
            type: "Percent",
            value: 20
          },
          centerX: {
            type: "Percent",
            value: 50
          },
          paddingTop: 0,
          paddingBottom: 0
        }
      },
      {
        type: "Legend",
        settings: {
          centerX: {
            type: "Percent",
            value: 50
          },
          x: {
            type: "Percent",
            value: 70
          },
          centerY: {
            type: "Percent",
            value: 50
          },
          y: {
            type: "Percent",
            value: 50
          },
          layout: "vertical",
          marker: "circle"
        },
        properties: {
          data: "#series.dataItems",
          markerRectangles: {
            properties: {
              template: {
                settings: {
                  cornerRadiusTL: 15,
                  cornerRadiusTR: 15,
                  cornerRadiusBL: 15,
                  cornerRadiusBR: 15
                }
              }
            }
          }
        }
      }
    ]
  },
  {
    parent: root.container
  }
);

Updated CodePen: https://codepen.io/team/amcharts/pen/MWMBVMx/344d95bb965694d8dd3fa695f00835ce?editors=0010

Related docs: https://www.amcharts.com/docs/v5/concepts/serializing/#Templates

flaming-cl commented 4 weeks ago

Wow, @martynasma thanks for the prompt response! yeah, it solves my problem. btw, a further question:

Customize legend background color and border**

Do you think it's possible to modify the legend background color and add border left like this, using JSON config?

image

Applying custom formatting logic to PieChart legend values

When using JSON config, how do we set custom formatting logic to PieChart legend values?

My code I tried doesn't seem to work

am5plugins_json.JsonParser.new(root)
    .parse(pieChartJson, {
      parent: root.container
    })
    .then(function (chart) {
      // Make stuff animate on load
      // https://www.amcharts.com/docs/v5/concepts/animations/#Forcing_appearance_animation
      chart.series.getIndex(0).appear(1000)
      chart.appear(1000, 100)

      const legend = chart.children?._values?.find(
        c => c.className === 'Legend'
      )
      legend.valueLabels.template.adapters.add('text', function (text, target) {
        return text + '%'
      })
    })
})
martynasma commented 4 weeks ago

For background, you will need a setup function:

properties: {
  data: "#series.dataItems",
  itemContainers: {
    properties: {
      template: {
        properties: {
          setup: function(target) {
            target.set("background", am5.Rectangle.new(root, {
              fill: am5.color(0x000000),
              fillOpacity: 0.3
            }))
          }
        }
      }
    }
  },
  markerRectangles: {
    properties: {
      template: {
        settings: {
          cornerRadiusTL: 15,
          cornerRadiusTR: 15,
          cornerRadiusBL: 15,
          cornerRadiusBR: 15
        }
      }
    }
  }
}

There's no way to add a border on a single side, though.

For format, why not use in-line number formatting if all you need is to add a percent sign?

flaming-cl commented 4 weeks ago

Hey @martynasma, thanks for the suggestions!

For format, we may add %, or may add comma separator + currency symbol + format precision (e.g. USD $123,456.78). Would you let us know if in-line number formatting also suits this need? (If so, would you give a code example for that

martynasma commented 4 weeks ago

Yes, you can do so with number formatting.

Except if you want to change thousands and decimals separator symbols, you will need to do that via locale: https://www.amcharts.com/docs/v5/concepts/locales/creating-translations/#Modifying_individual_prompts

flaming-cl commented 3 weeks ago

Thanks! Number formatting works for me.

1. Pie chart tooltip styles

btw, with JSON config, do you know how to set Pie chart tooltip styles? (e.g. make the tooltip background color to be grey and set the text color to be white?

The code below doesn't work:

{
      "series": {
        "type": "PieSeries",
        "settings": {
          "name": "Series",
          "categoryField": "country",
          "valueField": "sales",
          "legendLabelText": "[bold #5a5a5a]{category}[/]",
          "legendValueText": "[#5a5a5a]{value}[/]",
          "innerRadius": {
            "type": "Percent",
            "value": 65
          },
          "radius": {
            "type": "Percent",
            "value": 80
          },
          "width": {
            "type": "Percent",
            "value": 95
          },
          "x": {
            "type": "Percent",
            "value": 60
          },
          "y": {
            "type": "Percent",
            "value": 7
          },
          "centerX": {
            "type": "Percent",
            "value": 12
          }
        },
        "properties": {
          "data": "#data",
          "slices": {
            "properties": {
              "template": {
                "settings": {
                  "stroke": "white",
                  "strokeWidth": 1
                }
              }
            }
          },
          "tooltip": {
            "properties": {
              "template": {
                "settings": {
                  "fill": "#000",
                  "labelText": "[#fff]{value}[/]"
                }
              }
            }
          }
        }
      }
    }

2. legend layout

Do you think it's possible to layout legends like this? (like setting a width for the whole legend section, and display flex + flex wrap)

martynasma commented 3 weeks ago

Updated CodePen: https://codepen.io/team/amcharts/pen/MWMBVMx/344d95bb965694d8dd3fa695f00835ce?editors=0010

flaming-cl commented 3 weeks ago

Updated CodePen: https://codepen.io/team/amcharts/pen/MWMBVMx/344d95bb965694d8dd3fa695f00835ce?editors=0010

Many thanks @martynasma !!! btw, except setting up legend item container stroke, do you think there is another way to set gaps/margin between the item containers, use JSON config?

Screenshot from Codepen

image

Expected Behavior

image

martynasma commented 3 weeks ago

Yes, you can use marginTop, marginRight, etc. on item container's template.

flaming-cl commented 3 weeks ago

Yes, you can use marginTop, marginRight, etc. on item container's template.

btw @martynasma, do you know what's the right way to set up legends and bullets for XY chart? Tried example from the docs for setting up bullets, but it doesn't seem to work for me

{
  "refs": [
    {
      "data": [
        { "date": 1652425200000, "value": 92 },
        { "date": 1652511600000, "value": 95 },
        { "date": 1652598000000, "value": 100 },
        { "date": 1652684400000, "value": 100 },
        { "date": 1652770800000, "value": 96 },
        { "date": 1652857200000, "value": 97 },
        { "date": 1652943600000, "value": 94 },
        { "date": 1653030000000, "value": 89 },
        { "date": 1653116400000, "value": 89 },
        { "date": 1653202800000, "value": 87 },
        { "date": 1653289200000, "value": 84 },
        { "date": 1653375600000, "value": 81 },
        { "date": 1653462000000, "value": 85 },
        { "date": 1653548400000, "value": 89 },
        { "date": 1653634800000, "value": 86 },
        { "date": 1653721200000, "value": 90 },
        { "date": 1653807600000, "value": 93 },
        { "date": 1653894000000, "value": 94 },
        { "date": 1653980400000, "value": 94 },
        { "date": 1654066800000, "value": 96 }
      ]
    },
    {
      "xAxis": {
        "type": "DateAxis",
        "settings": {
          "maxDeviation": 0.5,
          "baseInterval": {
            "timeUnit": "day",
            "count": 1
          },
          "renderer": {
            "type": "AxisRendererX",
            "settings": {
              "pan": "zoom"
            }
          },
          "tooltip": {
            "type": "Tooltip"
          }
        }
      }
    },
    {
      "yAxis": {
        "type": "ValueAxis",
        "settings": {
          "maxDeviation": 1,
          "renderer": {
            "type": "AxisRendererY",
            "settings": {
              "pan": "zoom"
            }
          }
        }
      }
    }
  ],
  "type": "XYChart",
  "settings": {
    "panX": false,
    "panY": false,
    "wheelX": "panX",
    "wheelY": "zoomX",
    "cursor": {
      "type": "XYCursor",
      "settings": {
        "behavior": "zoomX"
      },
      "properties": {
        "lineY": {
          "settings": {
            "visible": false
          }
        }
      }
    }
  },
  "properties": {
    "xAxes": ["#xAxis"],
    "yAxes": ["#yAxis"],
    "series": [
      {
        "type": "LineSeries",
        "settings": {
          "name": "Series",
          "xAxis": "#xAxis",
          "yAxis": "#yAxis",
          "valueYField": "value",
          "valueXField": "date",
          "tooltip": {
            "type": "Tooltip",
            "settings": {
              "labelText": "{valueX}: {valueY}"
            }
          }
        },
        "bullets": [
          {
            "type": "Bullet",
            "settings": {
              "sprite": {
                "type": "Circle",
                "settings": {
                  "radius": 5,
                  "fill": {
                    "type": "Color",
                    "value": "#000"
                  }
                }
              }
            }
          }
        ],
        "properties": {
          "data": "#data"
        }
      }
    ]
  },
  "children": [
    {
      "type": "Legend",
      "settings": {
        "marginBottom": 3,
        "strokeWidth": 3,
        "textAlign": "center",
        "layout": "horizontal"
      },
      "properties": {
        "data": "#data"
      }
    }
  ]
}
martynasma commented 3 weeks ago

bullets needs to go into series' properties.

flaming-cl commented 3 weeks ago
{
  "refs": [
    {
      "data": [
        { "date": 1652425200000, "value1": 92, "value2": 32 },
        { "date": 1652511600000, "value1": 95, "value2": 45 },
        { "date": 1652598000000, "value1": 100, "value2": 20 },
        { "date": 1652684400000, "value1": 100, "value2": 100 },
        { "date": 1652770800000, "value1": 96, "value2": 69 },
        { "date": 1652857200000, "value1": 97, "value2": 90 },
        { "date": 1653894000000, "value1": 94, "value2": 64 }
      ]
    },
    {
      "xAxis": {
        "type": "DateAxis",
        "settings": {
          "maxDeviation": 0.5,
          "baseInterval": {
            "timeUnit": "day",
            "count": 1
          },
          "renderer": {
            "type": "AxisRendererX",
            "settings": {
              "pan": "zoom"
            }
          },
          "tooltip": {
            "type": "Tooltip"
          }
        }
      }
    },
    {
      "yAxis": {
        "type": "ValueAxis",
        "settings": {
          "maxDeviation": 1,
          "renderer": {
            "type": "AxisRendererY",
            "settings": {
              "pan": "zoom"
            }
          }
        }
      }
    }
  ],
  "type": "XYChart",
  "settings": {
    "panX": false,
    "panY": false,
    "wheelX": "panX",
    "wheelY": "zoomX",
    "cursor": {
      "type": "XYCursor",
      "settings": {
        "behavior": "zoomX"
      },
      "properties": {
        "lineY": {
          "settings": {
            "visible": false
          }
        }
      }
    }
  },
  "properties": {
    "xAxes": ["#xAxis"],
    "yAxes": ["#yAxis"],
    "series": [
      {
        "type": "LineSeries",
        "settings": {
          "name": "Series 1",
          "legendLabelText": "Series: {name}",
          "xAxis": "#xAxis",
          "yAxis": "#yAxis",
          "valueYField": "value1",
          "valueXField": "date",
          "tooltip": {
            "type": "Tooltip",
            "settings": {
              "labelText": "{value1}"
            }
          }
        },
        "properties": {
          "data": "#data",
          "bullets": [
            {
              "type": "Bullet",
              "settings": {
                "sprite": {
                  "type": "Circle",
                  "settings": {
                    "radius": 5,
                    "fill": {
                      "type": "Color",
                      "value": "#D29B00"
                    }
                  }
                }
              }
            }
          ]
        }
      },
      {
        "type": "LineSeries",
        "settings": {
          "name": "Series 2",
          "xAxis": "#xAxis",
          "yAxis": "#yAxis",
          "valueYField": "value2",
          "valueXField": "date",
          "legendLabelText": "Series: {name}",
          "tooltip": {
            "type": "Tooltip",
            "settings": {
              "labelText": "{value2}"
            }
          }
        },
        "properties": {
          "data": "#data",
          "bullets": [
            {
              "type": "Bullet",
              "settings": {
                "sprite": {
                  "type": "Circle",
                  "settings": {
                    "radius": 5,
                    "fill": {
                      "type": "Color",
                      "value": "#1B4B7D"
                    }
                  }
                }
              }
            }
          ]
        }
      }
    ]
  },
  "children": [
    {
      "type": "Legend",
      "properties": {
        "data": "#data"
      }
    }
  ]
}

Thanks @martynasma !!

  1. btw, do you know why legend was not showing in the XY chart? (l am using the same way showing legends in PieChart
  2. Do you know how to change the line color using JSON config?
martynasma commented 3 weeks ago

XY is a different chart, let start a new issue so this does not get a mile-long garbled thread.

flaming-cl commented 2 weeks ago

Hey @martynasma, about adding grey bg color to legend, if we increase the height of the legend, the marker/text are not in the center of the legend. Do you know how to solve this?

Screenshot 2024-09-12 at 12 00 05 PM

martynasma commented 2 weeks ago

Do you have an updated CodePen?

flaming-cl commented 2 weeks ago

Do you have an updated CodePen?

Hey, most of the code is the same as this one: https://codepen.io/team/amcharts/pen/MWMBVMx/344d95bb965694d8dd3fa695f00835ce?editors=0010

The only change is added height: 40 in legend item container

{
    refs: [
      {
        data: [
          {
            country: "France",
            sales: 100000
          },
          {
            country: "Spain",
            sales: 160000
          },
          {
            country: "United Kingdom",
            sales: 80000
          }
        ]
      },
      {
        series: {
          type: "PieSeries",
          settings: {
            name: "Series",
            valueField: "sales",
            innerRadius: {
              type: "Percent",
              value: 82
            },
            radius: {
              type: "Percent",
              value: 100
            },
            width: {
              type: "Percent",
              value: 100
            },
            categoryField: "country",
            tooltip: {
              type: "Tooltip",
              settings: {
                getFillFromSprite: false,
                autoTextColor: false,
                background: {
                  type: "PointedRectangle",
                  settings: {
                    fill: {
                      type: "Color",
                      value: 0xffffff
                    },
                    fillOpacity: 1
                  }
                },
              },
              properties: {
                label: {
                  settings: {
                    fill: {
                      type: "Color",
                      value: 0x000000
                    }
                  }
                }
              }
            }
          },
          properties: {
            data: "#data",
            labels: {
              properties: {
                template: {
                  settings: {
                    forceHidden: true
                  }
                }
              }
            },
            ticks: {
              properties: {
                template: {
                  settings: {
                    forceHidden: true
                  }
                }
              }
            }
          }
        }
      }
    ],
    type: "PieChart",
    settings: {
      layout: "horizontal"
    },
    properties: {
      series: ["#series"]
    },
    children: [
      {
        type: "Label",
        settings: {
          text: "[#5a5a5a]Total Rates[/]",
          fontSize: 18,
          fontWeight: "500",
          textAlign: "center",
          x: {
            type: "Percent",
            value: 25
          },
          y: {
            type: "Percent",
            value: 20
          },
          centerX: {
            type: "Percent",
            value: 50
          },
          paddingTop: 0,
          paddingBottom: 0
        }
      },
      {
        type: "Legend",
        settings: {
          centerX: {
            type: "Percent",
            value: 50
          },
          x: {
            type: "Percent",
            value: 70
          },
          centerY: {
            type: "Percent",
            value: 50
          },
          y: {
            type: "Percent",
            value: 50
          },
          layout: "grid",
          marker: "circle",
          width: 440
        },
        properties: {
          data: "#series.dataItems",
          itemContainers: {
            properties: {
              template: {
                settings: {
                  width: 220,
                  height: 40
                },
                properties: {
                  setup: function(target) {
                    target.set("background", am5.Rectangle.new(root, {
                      fill: am5.color(0x000000),
                      fillOpacity: 0.3
                    }))
                  }
                }
              }
            }
          },
          markerRectangles: {
            properties: {
              template: {
                settings: {
                  cornerRadiusTL: 15,
                  cornerRadiusTR: 15,
                  cornerRadiusBL: 15,
                  cornerRadiusBR: 15
                }
              }
            }
          }
        }
      }
    ]
  }
martynasma commented 1 week ago

Try minHeight instead of height:

settings: {
  width: 220,
  minHeight: 40
}