Plotly: How to customize xaxis tick labels using plotly express? - python

I'm trying to display a horizontal bar chart with dates on the x-axis, but can't seem a way to do that although the x-values are dates of type string. As you can see below, the numbers that occur as ticklabels have to be a summation of some sort, but I'm not sure exactly what. How can you change the example below to get dates as ticklabels?
Plot 1:
Code:
# imports
import numpy as np
import pandas as pd
import plotly.express as px
from datetime import datetime
# data
np.random.seed(1)
cols=list('ABCDE')
df = pd.DataFrame(np.random.randint(0,2,size=(5, len(cols))), columns=cols)
drng=pd.date_range(datetime(2020, 1, 1).strftime('%Y-%m-%d'), periods=df.shape[0]).tolist()
df['date']=[d.strftime('%Y-%m-%d') for d in drng]
dfm=pd.melt(df, id_vars=['date'], value_vars=df.columns[:-1])
# plotly express
fig = px.bar(dfm, x="date", y="variable", color='value', orientation='h',
hover_data=["date"],
height=400,
color_continuous_scale=['blue', 'teal'],
title='Custom date ticklabels for vertical bar plot',
template='plotly_white',
)
fig.update_traces(showlegend=False)
fig.update(layout_coloraxis_showscale=False)
fig.show()
What I've tried:
I've tried different combinations for tickmode, tickvals and ticktext for xaxis=dict() in fig.update_layout, alas with completely useless results.
Attempt 2: ticktext
Set tickvals=df['date']
fig.update_layout(yaxis=dict(title=''),
xaxis=dict(title='',
gridcolor='grey',
#tickmode= 'array',
#tickmode= 'linear',
#tick0= 2220,
#dtick=200,
#tickvals= [2020, 2040],
ticktext = df['date'])
)
Plot 2:
Same as before:
Attempt 3: ticktext & dtick
To my amazement, setting dtick to some arbitrary value gives you the plot below.
fig.update_layout(yaxis=dict(title=''),
xaxis=dict(title='',
gridcolor='grey',
#tickmode= 'array',
#tickmode= 'linear',
tick0= 2050,
dtick=2,
#tickvals= [2020, 2040],
ticktext = df['date'])
)
Plot 3:
Still amazingly useless, but now the ticks at least looks like dates, although we're looking at a value that represents a timestamp in 2008 and the source data is 2020...
Attempt 4: tickvals and ticktext
fig.update_layout(yaxis=dict(title=''),
xaxis=dict(title='',
gridcolor='grey',
#tickmode= 'array',
#tickmode= 'linear',
tick0= 2050,
#dtick=2,
tickvals= [2050, 2100, 2150, 2200],
ticktext = df['date'])
)
Plot 4:
From the looks of if, this is exactly what I'm looking for:
But this is equally useless like the other attempts, since we have to specify tickvals= [2050, 2100, 2150, 2200]. If we change the period, these values will have to be re-specified, and that's not very flexible. Of course, if we somehow could retrieve the default tickvalues used by plotly, we could easily replace them with the dates in the dataset. But that seems to still be impossible according to the answer to the post Plotly: How to retrieve values for major ticks and gridlines?
I'm at a complete loss here, and baffled by the uselessness of my attempts, so any other suggestions would be great!

You must activate tickmode to 'array' and then define tickvals and ticktext, like:
tickmode = 'array',
tickvals = [2050, 2100, 2150, 2200],
ticktext = df['date'])

Related

Insert space between ticks on y-Axsis / Control height of ticks on Python Plotly

I have a linegraph with twolines it in. On the x-Axis there is the time, on the y-Axes the values. On the y-Axis I want to set the space between the ticks manually.
My data is very dense in the range from 0 - 5, so I want the ticks in this range to be far away from each other in order distinguish between the two lines plotted in the graph.
Between 5 - 10 my data has more or less the same values, so the ticks can be closer together here.
From 10 - 15 need to spread the ticks again because my data is dense here.
I tried setting the values of the ticks manually, but that does not add/remove space/height of the ticks
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
df['Date']=pd.to_datetime(df['Date'])
dfg = df.groupby([pd.Grouper(key='Date', freq='M'), 'direction']).size().to_frame('counts')
dfg.reset_index(inplace=True)
layout = Layout(
title='Foo',
plot_bgcolor='rgba(0,0,0,0)',
yaxis = dict(
tickmode = 'array',
tickvals = [0, 0.5, 1, 1.5, ..., 5, 6, 7, ..., 10.5, 11, 11.5, 12, ...],
)
)
fig = go.Figure()
for d,c in zip(dfg['direction'].unique(), ['red','green']):
dfs = dfg.query('direction == #d')
fig.add_trace(
go.Scatter(
x=dfs['Date'],
y=dfs['counts'],
mode='lines',
line=dict(
color=c,
width=3
),
name=d
)
)
fig.show()
Note: The data I added here is not my real data. It's just some data to work with.
You need to scale your y data as you want, and then provide the ticks values and tick text
Assume:
y=[1,1.1,1.2,1.3,5,10,11,11.1,11.2,11.3]
y_trans=custom_trans(y) -> [1,2,3,4,5,6,7,8,9,10] # index
----------
go.Scatter(,y=y_trans,)
----------
fig.update_yaxes(
ticktext=["1", "1.1", "1.2", "5","10", ...],
tickvals=[1,2,3,5,6,..] #index position from y_trans
)
This is a very weird request though, and I would rather plot the difference in the two lines if it makes sense, or choose another method of visualizing, try log y axis?

How plot points based on categorical variable in plotly

I am using Plotly for visualization. I want to make plot, and give the points colors based on categorical variable.
fig = go.Figure()
fig.add_trace(go.Scatter(x=df.Predicted, y=df.Predicted,colors='Category',mode='markers',
))
fig.add_trace(go.Scatter(x=df.Predicted, y=df.real , colors='Category'
))
fig.show()
where Category is column in my dataframe. How can I do this kind of graph
you have implied a data frame structure which I have simulated
it's simpler to use Plotly Express higher level API that graph objects
have used to calls to px.scatter() to generate traces defined in your question. Plus have renamed traces in second call to ensure legend is clear and made them lines
import numpy as np
import pandas as pd
import plotly.express as px
df = pd.DataFrame(
{
"Predicted": np.sort(np.random.uniform(3, 15, 100)),
"real": np.sort(np.random.uniform(3, 15, 100)),
"Category": np.random.choice(list("ABCD"), 100),
}
)
px.scatter(df, x="Predicted", y="Predicted", color="Category").add_traces(
px.line(df, x="Predicted", y="real", color="Category")
.for_each_trace(
lambda t: t.update(name="real " + t.name)
) # make it clear in legend this is second set of traces
.data
)

Plotly: Hide date in axis ticks but show in hoverlabel title created with `x unified`

In the axis ticklabels, I want to show only the month and the year (grouped), like this -
But that also means I have to sacrifice on the day of the date (1-31) in the hoverlabel title. Is there a way I can hide the day part of the date on the axis (with grouped years and short month) and yet see it on the hoverlabel title? Something like this but without the 01s before each month on the axis.
Here's the code to reproduce the graph-
import plotly.express as px
df = px.data.stocks()
fig = px.line(df, x='date', y=['GOOG','AAPL'])
fig.update_layout(hovermode='x unified', xaxis_title=None, yaxis_title=None, xaxis_tickformat='%d%b\n%Y',
hoverlabel=dict(namelength=0))
fig.update_traces(hovertemplate=None)
# fig.update_traces(hovertemplate='%{x|%d%b,%Y} value: %{y:.2f}')
You can modify the parameter xaxis_hoverformat in the update_layout method. In this case, you don't need to use a hovertemplate.
import plotly.express as px
df = px.data.stocks()
fig = px.line(df, x='date', y=['GOOG','AAPL'])
fig.update_layout(
hovermode='x unified',
xaxis_title=None,
yaxis_title=None,
xaxis_tickformat='%b\n%Y',
xaxis_hoverformat='%d%b,%Y',
hoverlabel=dict(namelength=0)
)
fig.update_traces(hovertemplate=None)
fig.show()

Plotly Express: Plotting individual columns of a dataframe as multiple plots (scrollable) using plotly express

I posed a question at Plotly: How to add a horizontal scrollbar to a plotly express figure? asking how to add a horizontal scrollbar to a plotly express figure for purposes of visualizing a long multivariate time series. A solution for a simple example consisting of three series having 100K points each was given as follows:
import plotly.express as px
import numpy as np
import pandas as pd
np.random.seed(123)
e = np.random.randn(100000,3)
df=pd.DataFrame(e, columns=['a','b','c'])
df['x'] = df.index
df_melt = pd.melt(df, id_vars="x", value_vars=df.columns[:-1])
fig=px.line(df_melt, x="x", y="value",color="variable")
# Add range slider
fig.update_layout(xaxis=dict(rangeslider=dict(visible=True),
type="linear"))
fig.show()
This code is nice, but I'd like to have the plots not superimposed on a single set of axes--instead one above the other as would be done with subplot. For example, signal 'a' would appear above signal 'b', which would appear above signal 'c'.
Because my actual time series have at least 50 channels, a vertical scrollbar will likely be necessary.
As far as I know, it may be possible in dash, but it does not exist in plotly. The question you quoted also suggests a range slider as a substitute for the scroll function. At the same time, the range slider is integrated with the graph, so if you don't make the slider function independent, it will disappear on scrolling, which is not a good idea. I think the solution at the moment is to have 50 channels side by side and add a slider.
import plotly.graph_objects as go
import numpy as np
import pandas as pd
np.random.seed(123)
e = np.random.randn(100000,3)
df=pd.DataFrame(e, columns=['a','b','c'])
df['x'] = df.index
df_melt = pd.melt(df, id_vars="x", value_vars=df.columns[:-1])
fig = go.Figure()
fig.add_trace(go.Scatter(x=df_melt.query('variable == "a"')['x'],
y=df_melt.query('variable == "a"')['value'], yaxis='y'))
fig.add_trace(go.Scatter(x=df_melt.query('variable == "b"')['x'],
y=df_melt.query('variable == "b"')['value'], yaxis='y2'))
fig.add_trace(go.Scatter(x=df_melt.query('variable == "c"')['x'],
y=df_melt.query('variable == "c"')['value'], yaxis='y3'))
# Add range slider
fig.update_layout(
xaxis=dict(
rangeslider=dict(visible=True),
type="linear"),
yaxis=dict(
anchor='x',
domain=[0, 0.33],
linecolor='blue',
type='linear',
zeroline=False
),
yaxis2=dict(
anchor='x',
domain=[0.33, 0.66],
linecolor='red',
type='linear',
zeroline=False
),
yaxis3=dict(
anchor='x',
domain=[0.66, 1.0],
linecolor='green',
type='linear',
zeroline=False
),
)
fig.show()

plotly: how to add different vertical lines in strip plot with categorical x-axis

I have a simple strip plot with a categorical x-axis. I want to add a vertical line (on different y-values) for each category.
I am able to to create one vertical line throughout the plot like this:
import plotly.express as px
fig = px.strip(df, x="category", y="value")
fig.add_hline(y=191)
Result looks like this:
However, I am unable to plot one vertical line for each category.
Desired Output
My desired output is something like this:
I tried adding a shape to the layout, but it did not affect the output:
fig.update_layout(shapes=[
dict( type= 'line',
yref= 'paper', y0= 180, y1= 180,
xref= 'x', x0= "cat1", x1= "cat1")])
Something like this would probably work if the x-axis is numeric. However, not sure how to specify the category here. If this is the way to go, then I am probably doing it wrong.
How would I be able to add a single horizontal line, as depcited above, with a different y-value for each category?
Data to reproduce plot:
import pandas as pd
df = pd.DataFrame(data={
"category": ["cat1", "cat1", "cat2", "cat2"],
"value": [150, 160, 180, 190]
})
Add lines with shapes. There are two types of coordinate axes: x,y axis and paper-based. From your desired output, you can read and specify the x-axis as paper-based and the y-axis as the y-axis value.
import pandas as pd
import plotly.express as px
df = pd.DataFrame({'category':['cat1','cat1','cat2','cat2'],'value':[150,160,180,190]})
fig = px.strip(df, x="category", y="value")
fig.update_layout(shapes=[dict(type='line', x0=0.2, y0=180, x1=0.3, y1=180,
xref='paper', yref='y',
line_width=3, line_color='red'),
dict(type='line', x0=0.7, y0=192, x1=0.8, y1=192,
xref='paper', yref='y',
line_width=3, line_color='red'),
])
fig.show()

Categories