2

I want the currency sign as a prefix to the x-axis in a plotly subplot, the commands are fine because it works elsewhere but it just seems to play up when it integrates with the subplot functions.

import pandas as pd
import numpy as np
import plotly.graph_objs as go
from plotly.subplots import make_subplots
import random

x = np.array(["France", "Spain", "Italy", "Chile"])

df = pd.DataFrame({"country": np.repeat(x, [10,10,10,10]).tolist(),
                       "rating": random.sample(range(0,100),40),
                      "price": random.sample(range(100,1000),40)})

scatter = make_subplots(rows = 2, cols = 2, shared_yaxes = True, shared_xaxes = True,
                        
                   subplot_titles = ("France", "Spain", "Italy", "Chile"),
                        x_title = "Price", y_title = "Rating"
                   )

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="France", "price"],
                            y = df.loc[df["country"]=="France", "rating"],
                            mode = "markers"),
                            row = 1, col = 1)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Spain", "price"],
                            y = df.loc[df["country"]=="Spain", "rating"],
                            mode = "markers"),
                            row = 1, col = 2)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Italy", "price"],
                            y = df.loc[df["country"]=="Italy", "rating"],
                            mode = "markers"),
                            row = 2, col = 1)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Chile", "price"],
                            y = df.loc[df["country"]=="Chile", "rating"],
                            mode = "markers"),
                            row = 2, col = 2)

scatter.update_layout(showlegend = False, plot_bgcolor = "white",
                     xaxis = dict(showtickprefix = "all", tickprefix = "£"))

scatter.show()

If I remove the shared x and y axes commands then the currency will appear only on the bottom left subplot but I don't want to remove this really.

Does anyone know any way around this, please?

Update

I'm currently creating the following graph: enter image description here

and I want to be able to create the following: enter image description here

FluffySheep1990
  • 381
  • 3
  • 16

2 Answers2

2

I think that this is pretty similar to this answer The idea is to update every single trace using for_each_xaxis and for_each_yaxis as following.

Data

import pandas as pd
import numpy as np
import plotly.graph_objs as go
from plotly.subplots import make_subplots
import random

x = np.array(["France", "Spain", "Italy", "Chile"])

df = pd.DataFrame({"country": np.repeat(x, [10,10,10,10]).tolist(),
                       "rating": random.sample(range(0,100),40),
                      "price": random.sample(range(100,1000),40)})

Plot

scatter = make_subplots(rows = 2, cols = 2,
                        shared_yaxes = True, shared_xaxes = True,
                        subplot_titles = ("France", "Spain", "Italy", "Chile"),
                        x_title = "Price", y_title = "Rating")

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="France", "price"],
                            y = df.loc[df["country"]=="France", "rating"],
                            mode = "markers"),
                            row = 1, col = 1)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Spain", "price"],
                            y = df.loc[df["country"]=="Spain", "rating"],
                            mode = "markers"),
                            row = 1, col = 2)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Italy", "price"],
                            y = df.loc[df["country"]=="Italy", "rating"],
                            mode = "markers"),
                            row = 2, col = 1)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Chile", "price"],
                            y = df.loc[df["country"]=="Chile", "rating"],
                            mode = "markers"),
                            row = 2, col = 2)

# New stuff from here
scatter = scatter.update_layout(showlegend = False, plot_bgcolor = "white")

def update_y(y):
    y.update(matches=None)
    y.showticklabels=True
    
def update_x(x):
    x.update(matches=None)
    x.showticklabels=True
    x.tickprefix = "£"
    
scatter.for_each_yaxis(update_y)
scatter.for_each_xaxis(update_x)

enter image description here

Using plotly.express

If you like you could eventually use plotly express but in this case you need to deal with annotations too.


import plotly.express as px

fig = px.scatter(
           df,
           x="price",
           y="rating",
           color="country",
           facet_col="country",
           facet_col_wrap=2,
           facet_row_spacing=0.2, # default is 0.07 when facet_col_wrap is used
           facet_col_spacing=0.04, # default is 0.03
           )

fig = fig.update_layout(showlegend = False, plot_bgcolor = "white")
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))

def update_y(y):
    y.update(matches=None)
    y.showticklabels=True
    y.title.text = ""
    
def update_x(x):
    x.update(matches=None)
    x.showticklabels=True
    x.tickprefix = "£"
    x.title.text = ""


fig.for_each_yaxis(update_y)
fig.for_each_xaxis(update_x)

extra_annotations =[
        go.layout.Annotation(
            {
                'showarrow': False,
                'text': 'Price',
                'x': 0.5,
                'xanchor': 'center',
                'xref': 'paper',
                'y': 0,
                'yanchor': 'top',
                'yref': 'paper',
                'yshift': -30,
                'font': dict(
                    # family="Courier New, monospace",
                    size=16,
                    # color="#ffffff"
                    ),

            }),
         go.layout.Annotation(
            {
                'showarrow': False,
                'text': 'Rating',
                'x': 0,
                'xanchor': 'center',
                'xref': 'paper',
                'y': 0.7,
                'yanchor': 'top',
                'yref': 'paper',
                'xshift': -40,
                'textangle': -90,
                'font': dict(
                    # family="Courier New, monospace",
                    size=16,
                    # color="#ffffff"
                    ),

            })
        ]

annotations = list(fig.layout.annotations) + extra_annotations
fig.update_layout( annotations=annotations)

enter image description here

rpanai
  • 12,515
  • 2
  • 42
  • 64
  • Thanks for your response that's very helpful, is there a way to update the x axis for the top two subplots so that they're blank? As I wanted to avoid duplicating unnecessary detail. I've updated my initial post with pics of what I'm trying to achieve, I'm fairly sure I was able to do this when I used R – FluffySheep1990 Aug 31 '20 at 06:35
  • I'll have a look. I've to warn you that then the xticks (and yticks) on the subplots could differ. – rpanai Aug 31 '20 at 21:56
1

So I found out how to do it, you need to update the subplots individually with the code xaxisN_tickprefix = "£" with 'N' being the plot number of the graph. In this case I was trying to update plots 3 and 4, full code and graphs below.

import pandas as pd
import numpy as np
import plotly.graph_objs as go
from plotly.subplots import make_subplots
import random

x = np.array(["France", "Spain", "Italy", "Chile"])

df = pd.DataFrame({"country": np.repeat(x, [10,10,10,10]).tolist(),
                       "rating": random.sample(range(0,100),40),
                      "price": random.sample(range(100,1000),40)})

scatter = make_subplots(rows = 2, cols = 2, shared_yaxes = True, shared_xaxes = True,
                        
                   subplot_titles = ("France", "Spain", "Italy", "Chile"),
                        x_title = "Price", y_title = "Rating"
                   )

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="France", "price"],
                            y = df.loc[df["country"]=="France", "rating"],
                            mode = "markers"),
                            row = 1, col = 1)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Spain", "price"],
                            y = df.loc[df["country"]=="Spain", "rating"],
                            mode = "markers"),
                            row = 1, col = 2)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Italy", "price"],
                            y = df.loc[df["country"]=="Italy", "rating"],
                            mode = "markers"),
                            row = 2, col = 1)

scatter.add_trace(go.Scatter(x = df.loc[df["country"]=="Chile", "price"],
                            y = df.loc[df["country"]=="Chile", "rating"],
                            mode = "markers"),
                            row = 2, col = 2)

scatter.update_layout(showlegend = False, plot_bgcolor = "white",
                     #xaxis = dict(showtickprefix = "all", tickprefix = "£")  <- old code
                     xaxis3_tickprefix = "£", xaxis4_tickprefix = "£") #new code

scatter.update_xaxes(range = [0,1000]) #also added to ensure the axis align
scatter.update_yaxes(range = [0,100]) #also added to ensure the axis align

scatter.show()

enter image description here

FluffySheep1990
  • 381
  • 3
  • 16