Utilizing exponential formatting for Plotly axis scales

Following up on a previous question here: SO Q

The solution provided in the previous question uses JavaScript code to convert axis ticks into exponential format, but it only works for a single axis on a single plot.

When applied in a subplot() structure, it only affects the first plot and not all subplots in the final plot.

Here are the modifications I am seeking:

1: Solution should work on subplots. Attempts to call JavaScript in the build of each subplot resulted in all plots displaying without exponential formatting.

2: Make the solution work for both x and y axes. Previous attempts failed to achieve this requirement.

3: Ensure the solution does not cause issues when the axis is not numerical (as the application can also plot date columns).

4: If possible, display the exponential format as 1.23E+1 instead of 1E+1.

 library(shiny)
library(plotly)
library(htmlwidgets)


ui <- fluidPage(
    mainPanel(
     plotlyOutput('myplotly')
     )
  )

server <- function(input, output, session) {

  javascript <- "
function(el, x) 
{
  function fix_ticks()
  {
    ticks = Plotly.d3.selectAll('g.ytick').selectAll('text');
    ticks.forEach(function(tick) 
    {
      var num = parseInt(tick[0].innerHTML); 
      tick[0].innerHTML = num.toExponential();
    })
  }
  el.on('plotly_afterplot', fix_ticks);
}"


  output$myplotly <- renderPlotly({

    myplots <- lapply(unique(mtcars$cyl), function(v) {

    data <- mtcars[which(mtcars$cyl == v), ] 
      subp <-   plot_ly(data = data,
                x = rownames(data), 
                y = ~mpg,
                type = "bar")
      subp
     })

    p <- subplot(myplots, margin = 0.08)

    p$elementId <- NULL   ## to surpress warning of widgetid
    p <- onRender(p, javascript)

    p <- p %>% layout(margin =list(l = 60, r = 20, b = 160, t = 70) )

    p
  })
 }

shinyApp(ui = ui, server = server)

UPDATE Based on the recommendations provided, I have modified the code to check for numerical values and work for each axis. However, there are still some issues with handling negative values as it results in NaN. I have tried different approaches, including using tick[0].innerHTML and the forEach loop. It seems like a complete solution is still pending.

This is the code snippet I ended up using before encountering issues with negative values:

  javascriptMPP <- "
  function(el, x) 
  {
    function isNumber(n) {
      return (Object.prototype.toString.call(n) === '[object Number]' || Object.prototype.toString.call(n) === '[object String]') &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
    }
    function fixTicks()
    {
      ticks = Plotly.d3.selectAll('g.yaxislayer-above,g.xaxislayer-above').selectAll('text');
      ticks.each(function(d) 
      {
        if(parseInt(d.text) !== 0 )
        {
          var num = parseInt(d.text).toExponential(2);
          Plotly.d3.select(this).text(num);
        }
      })
    }
    el.on('plotly_afterplot', fixTicks);
  }"

Answer №1

Want to add exponential notation to subplots? If the plots are missing exponential notation, try modifying the d3 selector to be less specific and use the each method to change all ticks.

If you need to apply the modification to both x and y axes, simply adjust the selectAll statement to target the x-axis layer.

Concerned about non-numeric inputs causing issues in your calculations? Update your fixTicks functions to verify the input value's numeric nature. Dealing with date columns? Manual adjustments may be necessary.

To display exponential numbers with a specific number of digits after the decimal point, use num.toExponential(3).

Encountering NaN with negative tick values? Plotly uses a Unicode minus sign, which can be replaced in JavaScript.

Answer №2

I encountered various challenges but was able to resolve them with the help of the solution provided here.

The JavaScript code now supports negative values by replacing symbols to ensure functionality.

var num1 = parseInt(d.text.replace(/\\u2013|\\u2014|\\u2212/g, '-'));

If the value is 0, there is no need to convert it to exponential format.

if(parseInt(d.text) !== 0)

The code now handles text values correctly after converting symbols for negative numbers.

if(isNaN(num1)){

Additionally, I included a layout command in the plot code, adjusting the x-axis labels to a 45-degree angle to prevent overlap.

I made modifications to the dataset 'mtcars' to introduce negative and large numbers for testing purposes.

To display text values on the x-axis, the following code is now effective:

x = rownames(data),

rather than using a numerical parameter for x.

x = ~disp,

Below is the updated working code:

 (Code snippet has been revised for brevity)

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

The Jquery calculation feature sometimes mistakenly adds an incorrect value before calculating the correct value

Working on a calculator that accurately computes the field price and displays it, but facing an issue where the correct answer seems to merge with another value (likely from data-price as they match). Snippet of the code: var updateTotal = function() { ...

Please optimize this method to decrease its Cognitive Complexity from 21 to the maximum allowed limit of 15. What are some strategies for refactoring and simplifying the

How can I simplify this code to reduce its complexity? Sonarqube is flagging the error---> Refactor this method to reduce its Cognitive Complexity from 21 to the allowed 15. this.deviceDetails = this.data && {...this.data.deviceInfo} || {}; if (th ...

unleashing the magic of AJAX: a guide to extracting

In my Symfony project, I am attempting to retrieve the content of an AJAX request in order to check the data using dump(). The purpose is to process this data and perform a SQL query. However, when I use dump() in my controller, there doesn't appear t ...

Vue 3's defineExpose feature does not allow for the exposure of child methods or properties

I have a main component and subcomponent set up as shown below: Main Component : <script setup> import SubComp from '@/components/SubComp.vue' import { ref, computed } from 'vue' const subComp = ref(null) const handleClick = () ...

Error TS2322: Type 'boolean' cannot be assigned to type 'undefined'. What is the best approach for dynamically assigning optional properties?

I am currently working on defining an interface named ParsedArguments to assign properties to an object, and here is what it looks like: import {Rules} from "../Rules/types/Rules"; export interface ParsedArguments { //other props //... ...

Issue encountered with AngularJS .run not executing

It seems like the module is not functioning properly. In my index.js file, I have the following code: // index.js ---type 1 // .run not working... var myServiceToRun = require('./myservice.js'); var mod = angular.module('myApp',[]); mo ...

Adjusting diagram size based on screen width using Bootstrap and jQuery

I recently created a diagram that adjusts its size according to the screen width. However, when I implemented this code on my page, I encountered an issue where the final circle or glyph would drop to the next line instead of staying on the same line as in ...

Only retain rows in the dataframe that exist in another dataframe as well

Hello there, I have two sets of dataframes The first dataframe (DF1) looks like this: query Qstart Qend Col3 Col4 ABEL1 1 50 A B ABEL2 2 51 P O ABEL3 3 52 S E ABEL4 4 53 Q L ABEL5 5 54 A J And the second dataf ...

Troubleshooting ng-click not functioning within ng-repeat with database integration in MEAN Stack

//app.js var blogApp = angular.module('BlogApp', []); blogApp.controller('BlogController', function($scope, $http){ $scope.createPost = createPost; $scope.deletePost = deletePost; function init(){ getAllPosts(); } init(); ...

Issue with datetime picker in JavaScript/jQuery: Input fields added dynamically are not showing the datetime picker

I am currently investigating why the datetime picker does not work on a dynamically added input block within a table cell. A code snippet below serves as a proof of concept for this issue. In its present state, the default input tag (id: dti1) functions co ...

Changing the color of placeholder text in MUI 5 TextField

Looking to customize the text color and placeholder text color in my MUI TextField component to be green https://i.sstatic.net/NZmsi.png The documentation doesn't provide clear instructions, so I attempted a solution that didn't work: <TextF ...

The Cordova minification tool fails to compress files within the browser platform

I recently installed the cordova-minify plugin to compress the javascript code in my Cordova app. When I tried running the command: cordova build browser An output message appears: cordova-minify STARTING - minifying your js, css, html, and images. ...

Having trouble finding the element within the form tag even after attempting to use .switchTo().defaultContent()

My HTML is structured like this: <section> <div> <form> <div>Username field</div> <div>Password field</div> <div> <div>.. <div>.. <iframe& ...

How come my countdown application functions properly when accessed through the browser via the HTML page, but encounters issues when utilized with an HTTP server?

I have encountered an issue where the app functions correctly when I open the HTML file in my browser, but fails to load the CSS and JavaScript when accessing it through localhost:3000. HTML: <html> <head> <link href="./main.css" rel="st ...

Finding the occurrences of elements in an array using JavaScript

While browsing Stack Overflow, I stumbled upon a question that has yet to be answered: How can I count the occurrences of elements in a specific array using JavaScript?. let array = [6, 1, 5, 1, 1, 8, 2, 4, 6, 0] // Elements in array getOccurrence(array) ...

Create a time of 00:19:59 using JavaScript

I am attempting to display a countdown timer that starts at 20 minutes in the format (00:20:00) using setInterval. Once the countdown is finished, it should display as (00:00:00), but I am having trouble achieving this. <body onload = "onloadFunc();" ...

Locate the customers' IP addresses through an application built with ExpressJS

A few days back, I created a nodejs script for capturing user agents. While my script was functional, I faced difficulties in logging the REMOTE_ADDRESS of the client. app.js: var express = require('express'), http = require('http'), a ...

What is the correct way to pass a table record value to a jQuery function?

Within my php code, there is this snippet: echo "<td><button id='pausebut_{$record['idTrack']}' name='StopButton' type='Button' value='{$record['PreviewURL']}'>Stop</button> &l ...

"Implementing a feature to dynamically load Blogspot post content using JSON upon user

$.ajax({ url: 'https://uniquewebsite.com/feeds/posts/default?start-index=1&max-results=2&alt=json-in-script', type: 'get', dataType: "jsonp", success: function(data) { var entry = data.feed.entry; ...

Steps to include a title next to a progress bar:

Is there a way to achieve something like this? https://i.sstatic.net/dhO2f.jpg I attempted to use bootstrap but I ran into an issue where the title was slightly misaligned below the progress bar. Can someone offer assistance with this matter? Apologies i ...