I have recently started to produce scatterplot matrices via plotly.express. The plots reference custom data through a specialized hovertemplate. Here is an example:-
import plotly.express as px
import pandas as pd
df = pd.read_csv('./table.csv',dtype={'node':str,'ref_name':str,'population':int,'percent_use':float},keep_default_na=False,sep='\s\;\s',engine='python')
fig = px.scatter_matrix(df,
dimensions=['area', 'leakage', 'switch_power', 'internal_power', 'max_fall_drive', 'max_rise_drive'],
color='dont_use_status',
color_continuous_scale=px.colors.sequential.Bluered,
symbol='dont_use_status',
custom_data=['ref_name', 'population', 'percent_use', 'dont_use_status']
)
fig.update_traces(diagonal_visible=True,marker=dict(size=5))
fig.update_traces(hovertemplate=('<b>x: %{x}</b><br>'+'<b>y: %{y}</b><br>'+'<b>ref_name: %{customdata[0]}</b><br>'+'<b>population: %{customdata[1]}</b><br>'+'<b>percent_use: %{customdata[2]:.3f}</b><br>'+'<b>dont_use_status: %{customdata[3]}</b><br>'+'<extra></extra>'))
...and it works as intended; however, there is one little detail I cannot figure out: how do I replace the "x:" and "y:" in the hovertemplate with the actual x and y label names? Because it is a matrix, the x and y labels obviously change as you hover from one scatterplot to the next. I cannot seem to find the right keywords when searching. What %{} declaration is needed to dynamically retrieve the x axis and y axis labels?
Thanks!
Oy, found the answer right after posting. I need...
fig.update_traces(hovertemplate=('<b>%{xaxis.title.text}: %{x}</b><br>'+'<b>%{yaxis.title.text}: %{y}</b><br>'+'<b>ref_name: %{customdata[0]}</b><br>'+'<b>population: %{customdata[1]}</b><br>'+'<b>percent_use: %{customdata[2]:.3f}</b><br>'+'<b>dont_use_status: %{customdata[3]}</b><br>'+'<extra></extra>'))
...which is working.
Related
I've been attempting to create a line graph with subplots for each column of a dataframe in Pandas. My dataframe has variable names as the column names, datetime objects as the columns, and percentages (floats) as the values.
I'm referencing Plotly: How to create subplots from each column in a pandas dataframe?, but when adapted for my scenario it results in a blank figure - no exceptions or anything, and it does print out an empty box whose size I can adjust, but nothing in it.
My code is
from plotly.subplots import make_subplots
import plotly.graph_objects as go
# get the number of columns
num_alerts = len(helpfulness_graph_data.columns)
# Get the alert names
alert_types = helpfulness_graph_data.columns.values.tolist()
# Create a subplot figure object with 1 column, num_rows rows, and titles for each alert
fig = make_subplots(
rows=num_alerts, cols=1,
subplot_titles=alert_types)
j = 1
for i in helpfulness_graph_data.columns:
#print(helpfulness_graph_data[i].values)
fig.append_trace(
go.Scatter(
{'x': helpfulness_graph_data.index,
'y': helpfulness_graph_data[i].values}),
row=j, col=1)
j += 1
fig.update_layout(height=1200, width=600, title_text="Helpfulness Over Time")
fig.show()
For anyone else who comes across this: This happens when running plotly in jupyterlab sometimes apparently - I found some additional questions with suggested solutions, but none of them worked for me; What did work however was running it in plain old Jupyter. That's what I'd recommend.
I'm trying to make an animated plotly graph within R where both axes' min and max change during the animation. Someone recently asked this exact question for python, and it was solved by using layout update and looping through the "frames."
Python solution here: Is there a way to dynamically change a plotly animation axis scale per frame?
Here is the python code.
import plotly.express as px
df = px.data.gapminder()
df = df[(df['continent'] == 'Asia') & (df['year'].isin([1997, 2002, 2007]))]
scales = [2002]
fig = px.scatter(df, x="gdpPercap", y="lifeExp", animation_frame="year", animation_group="country",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=55, range_x=[100,100000], range_y=[25,90])
yranges = {2002:[0, 200]}
for f in fig.frames:
if int(f.name) in yranges.keys():
f.layout.update(yaxis_range = yranges[int(f.name)])
fig.show()
I've been looking through the R examples and the R plotly object, and I can't figure out... how would I apply this solution to R?
There's a solution using Shiny here, but the animation is much less smooth, it doesn't have the slider, and I don't know anything about shiny, so I'd rather avoid it if I could: https://community.plotly.com/t/what-is-the-most-performant-way-to-update-a-graph-with-new-data/639/6?u=fabern
In case it's useful, I wrote up my code to start recreating the example in R... as far as I could get.Maybe I need to be using plotly express or dash or some such?
library("gapminder")
library('data.table')
data(package = "gapminder")
df <- as.data.table(as.data.frame(gapminder))
df <- df[continent=='Asia' & year %in% c(1997, 2002, 2007)]
graph_animated <- plot_ly(df, x = ~gdpPercap, y = ~lifeExp, frame = ~year, size = ~pop,
type = 'scatter', color = ~continent)
The easiest way to do this is to build the plot and then add the change. You have to build first, in order to see the frames you want to modify.
# build
plt <- plotly_build(graph_animated)
# modify the layout for the second frame
plt$x$frames[[2]]$layout = list(yaxis = list(range = c(0, 200)))
After that, you can visualize it as you would any other plot.
I'm trying to add annoation to y axis based on different inverval of y value
if y > 0, I want to give the annotation of Flexion
if y < 0, I want to give the annotation of Extension
I tried to use multicategory to specify the annotation
my code is show below
import plotly.graph_objects as go
import numpy as np
x = np.arange(-10,10,1)
y = np.arange(-10,10,1)
y_annotation = [ 'Flexion' if data > 0 else 'Extension' for data in y ]
fig = go.Figure( data= go.Scatter(x=x,y=[y_annotation,y]) )
fig.show()
This will produce
but I don't want the lines to seperate the Flexision and Extension
and this method will give detailed y values on the y axis, which is also I don't want to have
I'm wondering if there's another way to add annotation to y axis based on different interval?
Thanks !
If you're happy with the setup above besides the lines and detailed y-axis, then you can drop the multi index approach and just set up annotations at the appropriate positions using fig.add_annotation()
The following figure is produced with the snippet below that:
makes room for your annotations on the left side using fig.update_layout(margin=dict(l=150)),
stores interval names and data in a dict, and
calculates the middle values of each specified interval, and
places the annotations to the left of the y-axis using xref="paper", and
does not mess up the values of the y-axis tickmarks.
Plot
Complete code:
import plotly.graph_objects as go
import numpy as np
x = np.arange(-10,10,1)
y = np.arange(-10,10,1)
y_annotation = [ 'Flexion' if data > 0 else 'Extension' for data in y ]
intervals = {'Flexion':[0,10],
'Extension':[0, -10]}
# plotly setup
fig = go.Figure( data= go.Scatter(x=x,y=y) )
# make room for annotations
fig.update_layout(margin=dict(l=150))
for k in intervals.keys():
fig.add_annotation(dict(font=dict(color="green",size=14),
#x=x_loc,
x=-0.16,
y=(intervals[k][0]+intervals[k][1])/2,
showarrow=False,
text="<i>"+k+"</i>",
textangle=0,
xref="paper",
yref="y"
))
fig.show()
I am aware of using axis=None to hide axis lines. But when you have actively used axis to modify the graph, is it possible to keep just the ticks, but hide the axis lines for both X and Y axis?
For example, here is a graph I have where I'd like it to happen -
import pandas as pd
import altair as alt
df = pd.DataFrame({'a': [1,2,3,4], 'b':[2000,4000,6000,8000]})
alt.Chart(df).mark_trail().encode(
x=alt.X('a:Q', axis=alt.Axis(titleFontSize=12, title='Time →', labelColor='#999999', titleColor='#999999', titleAlign='right', titleAnchor='end', titleY=-30)),
y=alt.Y('b:Q', axis=alt.Axis(format="$s", tickCount=3, titleFontSize=12, title='Cost →', labelColor='#999999', titleColor='#999999', titleAnchor='end')),
size=alt.Size('b:Q', legend=None)
).configure_view(strokeWidth=0).configure_axis(grid=False)
The output should look like the ticks in this SO post.
Note: The plot in that post has nothing to do with the demo provided here. its just for understanding purposes.
Vega-Lite calls the axis line the domain. You can hide it by passing domain=False to the axis configuration:
import pandas as pd
import altair as alt
df = pd.DataFrame({'a': [1,2,3,4], 'b':[2000,4000,6000,8000]})
alt.Chart(df).mark_trail().encode(
x=alt.X('a:Q', axis=alt.Axis(titleFontSize=12, title='Time →', labelColor='#999999', titleColor='#999999', titleAlign='right', titleAnchor='end', titleY=-30)),
y=alt.Y('b:Q', axis=alt.Axis(format="$s", tickCount=3, titleFontSize=12, title='Cost →', labelColor='#999999', titleColor='#999999', titleAnchor='end')),
size=alt.Size('b:Q', legend=None)
).configure_view(strokeWidth=0).configure_axis(grid=False, domain=False)
Using Blender created this model
that can be seen in A-frame in this link
This model is great and it gives an overview of what I'm trying to accomplish here. Basically, instead of having the names, I'd have dots that symbolize one specific platform.
The best way to achieve it with current state of the art, at my sight, is through Plotly 3D Scatter Plots. I've got the following scatterplot
import plotly.express as px
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/tiago-peres/immersion/master/Platforms_dataset.csv')
fig = px.scatter_3d(df, x='Functionality ', y='Accessibility', z='Immersion', color='Platforms')
fig.show()
that by going to this link you'll be able to click a button and open it in Colab
This nearly looks like the model. Yet, still in need to add three planes to the plot in specific locations. More precisely, in x=?, y=? and z=? (I'm using question mark because the value can be anything stablished).
In other words, want to add three planes to that scatterplot
x = 10
y = 30
z = 40
In the documentation, what closely resembles what I want was 3D Surface Plots.
I've done research and found two similar questions with R
Insert 2D plane into a 3D Plotly scatter plot in R
Add Regression Plane to 3d Scatter Plot in Plotly
I think you might be looking for the add_trace function in plotly so you can just create the surfaces and then add them to the figure:
Also, note, there's definitely ways to simplify this code, but for a general idea:
import plotly.express as px
import pandas as pd
import plotly.graph_objects as go
import numpy as np
fig = px.scatter_3d(df, x='Functionality ', y='Accessibility', z='Immersion', color='Platforms')
bright_blue = [[0, '#7DF9FF'], [1, '#7DF9FF']]
bright_pink = [[0, '#FF007F'], [1, '#FF007F']]
light_yellow = [[0, '#FFDB58'], [1, '#FFDB58']]
# need to add starting point of 0 to each dimension so the plane extends all the way out
zero_pt = pd.Series([0])
z = zero_pt.append(df['Immersion'], ignore_index = True).reset_index(drop = True)
y = zero_pt.append(df['Accessibility'], ignore_index = True).reset_index(drop = True)
x = zero_pt.append(df['Functionality '], ignore_index = True).reset_index(drop = True)
length_data = len(z)
z_plane_pos = 40*np.ones((length_data,length_data))
fig.add_trace(go.Surface(x=x, y=y, z=z_plane_pos, colorscale=light_yellow, showscale=False))
fig.add_trace(go.Surface(x=x.apply(lambda x: 10), y=y, z = np.array([z]*length_data), colorscale= bright_blue, showscale=False))
fig.add_trace(go.Surface(x=x, y= y.apply(lambda x: 30), z = np.array([z]*length_data).transpose(), colorscale=bright_pink, showscale=False))