Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mixed up axes assignments in subplots #1312

Closed
jackparmer opened this issue Jan 18, 2017 · 5 comments
Closed

Mixed up axes assignments in subplots #1312

jackparmer opened this issue Jan 18, 2017 · 5 comments
Labels
bug something broken

Comments

@jackparmer
Copy link
Contributor

https://plot.ly/~jackp/17340/

image

The traces in the bottom 2 subplot axes are assigned to axes (x2, y3) and (x3, y2). For clarity, this is how these assignments look in the JSON editor:

image

If I changes the axes assignments of these traces to the correct (x2, y2), (x3, y3), one of the subplots disappears - this is the bug. There seems to to be an issue with trace-axes assignment.

@jackparmer jackparmer added the bug something broken label Jan 18, 2017
@etpinard
Copy link
Contributor

Ok. Something is up when a layout has xaxis2/ yaxis2 but no xaxis and yaxis

Here's an more minimal reproducible example http://codepen.io/etpinard/pen/bggwQw

@jackparmer in the meantime, make xaxis2 -> xaxis etc and things should work: http://codepen.io/etpinard/pen/PWWGZv

@jackluo
Copy link

jackluo commented Jan 18, 2017

Maybe its just a bug in Python, but changing xaxis2/yaxis2 (1st subplot) + xaxis3/yaxis3 (2nd suplot) to xaxis/yaxis + xaxis2/yaxis2 as suggested doesn't seem to work, since the 1st subplot becomes blank once again...

screenshot 2017-01-18 15 19 42

@etpinard
Copy link
Contributor

@thejackluo can you paste your layout object?

@jackluo
Copy link

jackluo commented Jan 20, 2017

In[]:

Imports required libraries

from datetime import datetime
import numpy as np
import pandas as pd

import plotly.plotly as py
from plotly.graph_objs import *
from plotly.grid_objs import Grid, Column

mapbox_access_token = 'pk.eyJ1IjoiamFja2x1byIsImEiOiJjaXhzYTB0bHcwOHNoMnFtOWZ3YWdreDB3In0.pjROwb9_CEuyKPE-x0lRUw'

In[]:

Selects data

filename = "data/walmart_store_openings.csv"
chart_filename = "Walmart " + str(datetime.now())

df = pd.read_csv(filename, encoding = "utf-8-sig")

#df
#print(df.columns)

Gets list of years

years = [str(i) for i in range(1962,2007)]

Bug with Grid parsing if dataset isn't sanitized, need to return NaN instead of empty []

#years = df["YEAR"].unique()
#years = [str(i) for i in sorted(years)]

Groups by year and count number of stores

ylist = df.groupby("YEAR").count()["storenum"].astype(int)
ylist_cum = ylist.cumsum()

Gets max range for subplot (minimum set to 0, no y-axis jump)

max_range = max(ylist) * 1.15
max_range_cum = max(ylist_cum) * 1.15

Converts list items to string

ylist = [str(i) for i in ylist]
ylist_cum = [str(i) for i in ylist_cum]

In[]:

Uploads all 2 Grids

Since Grid has a size limit, it is good practice to upload

multiple Grids for suplots in case of large datasets

grid_filename = chart_filename + " Grid"
grid_filename2 = grid_filename + "2"

columns = []
columns2 = []

for i, year in enumerate(years):

# Filter df for current year only
current_year = df[df["YEAR"] == int(year)]

lons = list(current_year["LON"].astype(float))
lats = list(current_year["LAT"].astype(float))
texts = list(current_year["STRCITY"].astype(str))

# Iteratively grows list to create line/area animations
xvalues = years[:i+1]
yvalues = ylist[:i+1]
yvalues_cum = ylist_cum[:i+1]

columns.append(Column(lons, "x{}".format(i+1)))
columns.append(Column(lats, "y{}".format(i+1)))
columns.append(Column(texts, "text{}".format(i+1)))

columns2.append(Column(xvalues, "x{}".format(i+1)))
columns2.append(Column(yvalues, "y{}".format(i+1)))
columns2.append(Column(yvalues_cum, "y_cum{}".format(i+1)))

Will throw error if file exists or path is not root

grid = Grid(columns)
py.grid_ops.upload(grid, grid_filename, auto_open=False)

grid2 = Grid(columns2)
py.grid_ops.upload(grid2, grid_filename2, auto_open=False)

In[]:

Creates data

Main trace

trace1 = Scattermapbox(

# GENERAL
lonsrc = grid.get_column_reference('x1'),
latsrc = grid.get_column_reference('y1'),
textsrc = grid.get_column_reference('text1'),
mode = "markers",
hoverinfo = "lon+lat+text",

# SPECS
marker = dict(
    size = 10,
    color = "#54D9F3",
    opacity = "0.6",
),

)

Non-cumulative secondary

trace2 = Scatter(

# GENERAL
xsrc = grid2.get_column_reference('x1'),
ysrc = grid2.get_column_reference('y1'),
mode = "lines+markers",
hoverinfo = "x+y",

# SPECS
line = dict(
    color = "#4ADFD0",
),
marker = dict(
    symbol = "cross-thin-open",
),
xaxis = "x",
yaxis = "y",

)

Cumulative secondary

trace3 = Scatter(

# GENERAL
xsrc = grid2.get_column_reference('x1'),
ysrc = grid2.get_column_reference('y_cum1'),
mode = "lines",
fill = "tozeroy",
hoverinfo = "x+y",

# SPECS
line = dict(
    color = "#1CA9E2",
),
xaxis = "x2",
yaxis = "y2",

)

Note that subplots are mapped to opposite yaxis (temporary solution, bugfix impending)

In[]:

Sets up slider and buttons

slider = dict(

# GENERAL
plotlycommand = "animate",
values = years,
initialValue = years[0],
visible = True,

# ARGUMENTS
args = [
    "slider.value",
    dict(
        duration = 300,
        ease = "cubic-in-out",
    ),
],

)

sliders = dict(

# GENERAL
active = 0,
steps = [],

currentvalue = dict(
    font = dict(size = 16),
    prefix = "Year : ",
    xanchor = "right",
    visible = True,
),
transition = dict(
    duration = 300,
    easing = "cubic-in-out",
),

# PLACEMENT
x = 0.1,
y = 0,
pad = dict(t = 40, b = 10),
len = 0.9,
xanchor = "left",
yanchor = "top",

)

for year in years:

slider_step = dict(

        # GENERAL
        method = "animate",
        value = year,
        label = year,

        # ARGUMENTS
        args = [
            [year],
            dict(
                frame = dict(duration = 300, redraw = False),
                transition = dict(duration = 300),
                mode = "immediate",
                ),
            ],

        )

sliders["steps"].append(slider_step)

updatemenus = dict(

# GENERAL
type = "buttons",
showactive = False,
x = 0.1, #x = 1.1
y = 0, #y = 1
pad = dict(t = 60, r = 10),
xanchor = 'right',
yanchor = 'top',
direction = "left",

# BUTTONS
buttons=[
    dict(
        method = "animate",
        label = "Play",

        # PLAY
        args = [
            None,
            dict(
                frame = dict(duration = 300, redraw = False),
                fromcurrent = True,
                transition = dict(duration = 50, easing = "quadratic-in-out"), # easing = "cubic-in-out"
                mode = "immediate",
                ),
            ],
        ),
    dict(
        method = "animate",
        label = "Pause",

        # PAUSE
        args = [
            [None], # Note the list
            dict(
                frame = dict(duration = 0, redraw = False),
                mode = "immediate",
                transition = dict(duration = 0),
                ),
            ],
        ),
    ],

)

In[]:

Creates layout

layout = dict(

title = "Growth of Walmart stores, 1962-2006",

# GENERAL LAYOUT
width = 960,
height = 720,
autosize = True,
font = dict(
    family = 'Overpass',
    size = 12,
    color = "#CCCCCC",
),
margin = dict(
    t = 80,
    l = 80,
    b = 80,
    r = 80,
    pad = 2,
),
showlegend = False,
hovermode = "closest",

# ANIMATIONS
slider = slider,
sliders = [sliders],
updatemenus = [updatemenus],

# COLOR THEME
plot_bgcolor = "#191A1A",
paper_bgcolor = "#151515",

# MAPBOX
mapbox = dict(
    accesstoken = mapbox_access_token,
    center = dict(
        lon = -94.14,
        lat = 38.81,
    ),
    zoom = 3.0,
    style = "dark",
    domain = dict(
        x = [0, 1],
        y = [0.24, 1]
    ),
),

# AXIS (see current bug above)
xaxis = dict(
    range = ["1962", "2006"],
    domain = [0, 0.48],
    title = "Stores/year",
),
yaxis = dict(
    range = [0, max_range],
    domain = [0, 0.20],
    side = "left",
),

xaxis2 = dict(
    range = ["1962", "2006"],
    domain = [0.53, 1],
    title = "Total stores",
),
yaxis2 = dict(
    range = [0, max_range_cum],
    domain = [0, 0.20],
    side = "right",
),

)

In[]:

Creates frames

frames = []

for i, year in enumerate(years):

# Create frame for each subplot
frame_trace1 = dict(
    lonsrc = grid.get_column_reference("x{}".format(i+1)),
    latsrc = grid.get_column_reference("y{}".format(i+1)),
    textsrc = grid.get_column_reference("text{}".format(i+1)),
)

frame_trace2 = dict(
    xsrc = grid2.get_column_reference("x{}".format(i+1)),
    ysrc = grid2.get_column_reference("y{}".format(i+1)),
)

frame_trace3 = dict(
    xsrc = grid2.get_column_reference("x{}".format(i+1)),
    ysrc = grid2.get_column_reference("y_cum{}".format(i+1)),
)

# [0,1,2] specifies the 3 subplots to apply frames to
frame = dict(
    data = [frame_trace1, frame_trace2, frame_trace3],
    name = year,
    traces = [0,1,2],
)

frames.append(frame)

In[]:

Uploads animation

data = [trace1, trace2, trace3]
figure = dict(data=data, layout=layout, frames=frames)
py.icreate_animations(figure, filename=chart_filename, auto_open=False)

@etpinard
Copy link
Contributor

etpinard commented Feb 2, 2018

This bug appears fixed:

Plotly.d3.json('https://plot.ly/~jackp/17340.json', (err, fig) => {
  fig.data[1].xaxis = 'x2';
  fig.data[1].yaxis = 'y2';
  fig.data[2].xaxis = 'x3';
  fig.data[2].yaxis = 'y3';

  Plotly.newPlot(gd, fig.data, fig.layout);
});

gives (I believe) the desired result:

image


This was probably fixed in @alexcjohnson 's #2227 and/or #1854

@etpinard etpinard closed this as completed Feb 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken
Projects
None yet
Development

No branches or pull requests

3 participants