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

Dealing with the Back Button Problem in History API and History.js

Using Ajax to load the page presents a challenge when the user clicks the back button. Here is the scenario: Initial page (index.php) is loaded User clicks on a link The new page loads successfully via Ajax User clicks the back button The initial page is ...

What is the best way to place content in a single div without it being divided into several separate boxes

Here is my code snippet: <div class="col-md-9"> <div id="statbox"> {% for obj in product_type %} {% for obj1 in vastu %} <script type="text/javascript"&g ...

JavaScript code to enforce a 100% page zoom setting

After developing a small game in Canvas, I encountered an issue. Some users with their default zoom level set to something other than 100% are unable to view the entire game page. I attempted to resolve this by using the following CSS: zoom: 100%; This ...

Utilizing Symfony 4, Twig, and VueJS for Seamless Routing between Components

Currently diving into Symfony 4 with Twig templating and leveraging VueJS for UI elements. I've created a simple component in a .vue file to display tasks, which at the moment just generates a basic table. // task-list.vue <template> < ...

When I engage with the input field, it ceases to be in focus

Here is the code I've been working on: https://github.com/Michael-Liendo/url-shortener/blob/main/src/pages/index.js If you want to see the issue for yourself, check it out at: ...

Creating a responsive Google map within a div element: A step-by-step guide

I am experiencing difficulties with implementing a responsive Google map on my webpage. To achieve a mobile-first and responsive design, I am utilizing Google Map API v3 along with Bootstrap 3 CSS. My objective is to obtain user addresses either through th ...

Different ways to verify if a Checkbox is selected within a table

As a newcomer to reactjs, I have a component that renders two tables with different data using the same component and passing data through props. Each table has checkboxes for selection. If a user selects items from both tables, I want to detect if they ha ...

Angular 2 dropdown list that allows users to add a personalized value in the HTML code

Here is the scenario I am dealing with We are displaying a fixed dropdown list to the user For example, a dropdown list has 4 options such as apple, orange, grape, pineapple and 'create your own' If the user is not satisfied with the provided ...

Multiple components are returned with switch case

I am trying to iterate over an object and display a result based on Object.entries. However, the loop currently stops at the first return statement. Is there a way for me to capture and display all components returned simultaneously, perhaps using a vari ...

What is the specific function of $('id').on('click', this.method.bind(this)) in this scenario?

Check out the app I'm talking about here: I am delving into the bind method in JavaScript to grasp its essence. Upon experimenting with it in the console, my interpretation is that bind produces a duplicate of the function, wherein "this" is tethere ...

Issue with Vue CLI: NPM script "dev" fails to run following system restoration on Windows 7

Hey there, I'm having some trouble running vue js projects using the npm run dev command. I've tried several solutions to fix it: reinstalling NodeJs, updating npm, installing a fresh vue project via cli following the official documentation, ...

Ordering an array using Typescript within React's useEffect()

Currently, I am facing a TypeScript challenge with sorting an array of movie objects set in useEffect so that they are displayed alphabetically. While my ultimate goal is to implement various sorting functionalities based on different properties in the fut ...

What is the best way to create a new row within a Bootstrap table?

Struggling to format an array inside a table with the `.join()` method. The goal is to have each car on a separate row. Attempts using `.join("\r\n")` and `.join("<br />")` have been unsuccessful. What am I overlooking? ...

Is there a way to deactivate the click function in ngx-quill editor for angular when it is empty?

In the following ngx-quill editor, users can input text that will be displayed when a click button is pressed. However, there is an issue I am currently facing: I am able to click the button even if no text has been entered, and this behavior continues li ...

Transferring sizable JavaScript array to the Web API

I've been grappling with this problem for two days... In my JavaScript code, I have a large array comprising 20,000 rows and 41 columns. This data was initially fetched in JavaScript via an ajax call, as shown below: var dataArray = []; var dataRequ ...

Easy Ways to Personalize the Appearance of Your Material-UI Tab Indicator

I've been working on customizing the tab indicator in material-ui and so far I've only been able to make rectangular or square shapes. I'm wondering if there's a way to turn it into an arrow or an upside-down triangle instead? Here is ...

Looking to incorporate Slick Carousel as the main slider on my website for a dynamic hero section using JavaScript

Currently in the process of expanding my knowledge in javascript, I am now delving into setting up Slick Carousel. It is essential that it functions as a hero slider on my website. If you are interested in checking out Slick Carousel on github, feel free ...

Simplest method for defining an associative array

Looking to create an array in the format shown below: [0: 0, 1: 1, 2: 2] This is achieved using the following code snippet: var arr = []; for(i=0; i<3; i++){ arr[i] = i; } Upon execution, my array appears as follows: [0, 1, 2] The values with ...

There was an issue exporting bands on Google Earth Engines in Javascript due to incompatible data types: Float32 and UInt16 were found to be inconsistent

I am attempting to export a basic AOI of a Landsat-8 image, but I keep encountering the error mentioned in the title. Can you help me understand why this error is occurring? All the bands in my image are floats so I don't see where the issue lies. var ...

Can you provide guidance on utilizing OneNote JavaScript APIs to interpret indented paragraphs within OneNote?

I keep a notebook that contains the following entries: https://i.stack.imgur.com/MLdO0.png For information on OneNote APIs, you can refer to this link (paragraph class selected already) https://learn.microsoft.com/en-us/javascript/api/onenote/onenote.p ...