Creating a radial progress chart using Plotly JavaScript

I recently started working with the Plotly library and now I need to display a circular progress graph in Vuejs 2, like the one shown below.

While Plotly is a comprehensive tool, I have not come across an example that matches this specific design using JavaScript.

Your input or assistance would be greatly appreciated. Thank you!

Best regards!

The circular progress graph created with Plotly by Derek Example can be seen here:

https://i.stack.imgur.com/S1Gsn.png

My English may not be perfect, but please note the lack of smooth curvature in the circle line.

Answer №1

To replicate the elements of the chart, you can utilize plotly.js traces and text. By employing a scatter to position an array of markers, you can generate the grey arc first and then overlay the red arc above it. To compute the coordinates of each marker, center your axes at (0,0) and apply x=r*cos(theta) and y=r*sin(theta), where theta represents the angle in radians. This method helps in obtaining arrays of x and y values to delineate the desired sections of the red and grey arcs.

In order to achieve a circular chart resembling the one displayed, modify the x-axis and y-axis ranges to [-2,2], set the radius of the circular arcs as 0.9 with [0,0] as the center, assign size 10 to the markers of these arcs, establish the grey arc spanning from 210 to 85 degrees and the red arc ranging from 90 to -200 degrees by using the makeArr function introduced by mhodges in their solution here. Additionally, include a trace with a green marker but with null values to ensure its presence in the legend without appearing on the chart. Text traces can be applied for adding textual content around the center of the circular arcs.

For reference, you can access an example on codepen here:

// credit goes to mhodges: https://stackoverflow.com/a/40475362/5327068
function makeArr(startValue, stopValue, cardinality) {
  var arr = [];
  var step = (stopValue - startValue) / (cardinality - 1);
  for (var i = 0; i < cardinality; i++) {
    arr.push(startValue + (step * i));
  }
  return arr;
}

function getCircleCoords(r, center, degree_values) {
  var center_x = center[0];
  var center_y = center[1];
  var x_coords = [];
  var y_coords = [];
  for (var i = 0; i < degree_values.length; i++) {
    x_coords.push(center_x + (r * Math.cos(degree_values[i]*Math.PI/180)));
    y_coords.push(center_y + (r * Math.sin(degree_values[i]*Math.PI/180)));
  }
  return [x_coords, y_coords];
}

var trace1 = {
  x: [0],
  y: [0.15],
  text: ['1000'],
  mode: 'text',
  textfont: {
    family: 'arial',
    size: 28,
    color: 'black'
  },
  showlegend: false
};

var trace2 = {
  x: [0],
  y: [-0.15],
  text: ['kW/kg'],
  mode: 'text',
  textfont: {
    family: 'arial',
    size: 22,
    color: 'grey'
  },
  showlegend: false
};

circleCoords = getCircleCoords(r=0.9, center=[0,0], radian_values=makeArr(90,-200,1000))
backgroundCircleCoords = getCircleCoords(r=0.9, center=[0,0], radian_values=makeArr(210,85,1000))

var trace3 = {
  x: [null],
  y: [null],
  mode: 'markers',
  marker: {color: 'green', size: 10},
  name: 'Correcto funcionamiento'
};

var trace4 = {
  x: backgroundCircleCoords[0],
  y: backgroundCircleCoords[1],
  mode: 'markers',
  marker: {color: '#eeeeee', size: 10},
  name: null,
  showlegend: false
};

var trace5 = {
  x: circleCoords[0],
  y: circleCoords[1],
  mode: 'markers',
  marker: {color: 'red', size: 10},
  name: 'Funcionamiento erroneo'
};

var layout = {
  title:'Relacíon potencia peso',
  xaxis: {
    range: [-2, 2],
    zeroline: false,
    showgrid: false,
    zeroline: false,
    showline: false,
    showticklabels: false
  },
  yaxis: {
    range: [-2, 2],
    showgrid: false,
    zeroline: false,
    showline: false,
    showticklabels: false
  },
  width: 600,
  height: 600,
  legend: {
    x: 0,
    y: 0,
    "orientation": "h"
  }
};

var data = [trace1, trace2, trace3, trace4, trace5];
Plotly.newPlot('myDiv', data, layout);

https://i.stack.imgur.com/ARPiCm.png

EDIT: For smoother circle rendering, increase the number of markers used when drawing the circle:

circleCoords = getCircleCoords(r=0.9, center=[0,0], radian_values=makeArr(90,-200,5000))
backgroundCircleCoords = getCircleCoords(r=0.9, center=[0,0], radian_values=makeArr(210,85,5000))

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Seamless Integration of Hosted Fields by Braintree

I am currently struggling with setting up Braintree hosted fields on my registration form. Unfortunately, there are significant gaps between the fields which doesn't look appealing. Despite referring to the braintree documentation and guides, I find t ...

Adding schemas to the router of a Next.js 13 app is a helpful feature that can

Summary: In Next.js 13, the /app router's new changes to layout and page routing have altered how we add content to the <head>. The challenge now is how to include a schema script on each page. Next.js automatically combines <head> tags f ...

There seems to be an issue with accessing /puffins/5f298d0ebcbaf254dcf282b3 at

Having trouble with my destroy route - it keeps returning an error. I've spent a lot of time trying to debug it but no luck yet. Can you lend a hand? All other CRUD routes are functioning correctly. //THE ROUTE app.delete('/puffins/:id', (re ...

Tips for updating VUE's main.js file to incorporate the routers/index.js configuration

What is the reason for the difference in syntax between the VUE UI main.js code generated by CLI/3 and the older version, and how does it function? What are the various components of the new syntax and how do they work? sync(store, router) // for vuex-rou ...

What is the best way to tally the number of occurrences a value is true within an hour or day using React?

I am developing an alarm application and I want to track the number of times the alarm has been triggered within an hour and a day. Utilizing redux toolkit, I manage the state of the alarm (on/off) and have a reducer called countAlarm to increase the count ...

I am experiencing difficulties in running tests for the Vue3/TS/Jest/testing library

After using vue cli to create a project with vue3, TS, JEST, and adding @testing-library/vue, my package.json is structured as follows: { "name": "todo-app", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", ...

Adjusting the background hue of the 'td' element within an ajax request

When I press a button, an ajax call is triggered below. In this call, I append 'td' elements with values to a table. Specifically, on the line ''</td><td>' + result[i].preRiskCategory +', I am attempting to change ...

react-ga4 is sending multiple view events repeatedly

After setting up a Google Analytics account and creating a new property, I integrated the tracking ID with react-ga4 for my Album ItemPage as shown below: const ItemPage = () => { const {user} = useContext(AuthContext); let { item } = useParams ...

The React Component is limited to updating once

Exploring the React Native code below: import React from 'react'; import {Text, View, StyleSheet, Button} from 'react-native'; export default class Target extends React.Component { constructor(props){ super(props); ...

Trying to access a property that doesn't exist (fetching 'fetchBans')

My goal is to create a command within my Discord bot that can unban a user. However, when I finished writing the code, I encountered an error stating 'Cannot read properties of undefined (reading 'fetchBans'). Here is the section of code cau ...

Trigger the jQuery function once the external URL loaded via AJAX is fully loaded

Currently, I am in the process of developing a hybrid mobile app for Android and I am relatively new to this technology. I have two functions in jQuery, A and B. Function A is responsible for making an AJAX request to retrieve data from 4 external PHP fi ...

Incorporating and utilizing the HTML5-captured image as a point of reference

I understand that all I need to do to achieve this is insert <input type="file" id="photo" accept="image/*;capture=camera"> However, my lack of coding skills has caused issues with actually grabbing and using the image selected/taken by the user. ...

How can I alter the icon's color?

Is it possible for the icon's color to change to red when the condition is greater than 0, and to gray when the condition is equal to zero? <TouchableOpacity onPress={() => { if (Object.values(selectedIt ...

Enhance the performance of page loading and implement a consistent spinner feature to ensure smooth transitions for users in Next.js version 13

I am currently working on a project using Next.js 13, and I am encountering issues with slow loading times and an unstable spinner when navigating between pages. Specifically, when transitioning from the home page to the /example page, the experience is n ...

The response body from the HTTP request is consistently empty or undefined

While working with two containers managed by Docker Compose, I encountered an issue where the response body from a GET call made by a Node.js service in one container to an API in another container using the request module was consistently empty or undefin ...

Placing a group of input fields and a button based on the data-id attribute of the element

I have a form that appears when a button is clicked, and the save button saves input values into an object. Is there a more efficient way to write this function if I need to create 9 more buttons with different data-id attributes (e.g. data-id="2" and so ...

Issues occurring with setting the variable using the Google latlng API

I've tried searching for solutions on various forums, including stackoverflow, but haven't been able to make it work. The issue lies in this code snippet where the variable 'pos' is not being set: var geocoder= new google.maps.Geocoder ...

What is the best way to send information from a main blade to an included modal?

Trying to implement a functionality where a modal is triggered on clicking a button and an array named $incident is passed through to the properties of a Vue component. What is the correct way to pass data from a parent blade to an included modal? I initia ...

Ways to substitute numerous instances of a string in javascript

I have experience in developing websites using reactjs. I usually implement restAPI's with java and work with liferay CMS. In one of my projects, I created a shortcode for accordion functionality like this: ('[accordion][acc-header]Heading 1[/ac ...

JavaScript causing Axios network error

Recently, I've started exploring the combination of axios and stripe in my project but unfortunately, I have encountered some challenges. Whenever I attempt to initiate a post request using axios, an error pops up which looks like this: https://i.sta ...