How to add sucesive spots in plotly (python) using slider? - python

I am trying to make a plotly graph which could plot the evolution of a parameter's value along a period of time.
By now, what I've managed to get is plotting individual points. However, I'd like to keep the previos spots plotted while getting an increment on the slider.
My code:
import numpy as np
import plotly.express as px
import pandas as pd
df=pd.read_excel("file.xlsx")
fig=px.scatter(df, x="$R[\Omega]$", y="$X[\Omega]$", title='$U_1/I_1$',animation_frame="t[seg]")
fig["layout"].pop("updatemenus")
fig.show()
Data
df2=pd.DataFrame({"$R[\Omega]$":[-0.092034,-0.096416,-0.103026],
"$X[\Omega]$":[0.045707,0.047590,0.039953],
"t[seg]":[0.416244,0.417078,0.417912]})

have simulated data as I don't have access to your excel spreadsheet. Named columns consistently with what your code implies
need to make sure layout has axes ranges set for all data
after building figure, for each frame update the data in traces such that it contains all values from previous frames as well. (Note this assume that t[seg] is numeric)
full code
import numpy as np
import plotly.express as px
import pandas as pd
# df=pd.read_excel("file.xlsx")
# generate data in structure implied by question
df = pd.DataFrame(
{
"$R[\Omega]$": np.linspace(0, 100, 250),
"$X[\Omega]$": np.sin(np.linspace(0, 50, 250)),
"t[seg]": np.linspace(0, 100, 250) // 10,
}
)
xcol = "$R[\Omega]$"
ycol = "$X[\Omega]$"
fcol = "t[seg]"
fig = px.scatter(
df, x=xcol, y=ycol, title="$U_1/I_1$", animation_frame=fcol
)
fig["layout"].pop("updatemenus")
# prepare axes to show all values
fig.update_layout(
{
ax: {
"range": [
df[col].min(),
df[col].max(),
]
}
for ax,col in zip(["xaxis", "yaxis"], [xcol,ycol])
}
)
# add data into each frame from all preceeding traces
for fr in fig.frames[1:]:
df_ = df.loc[df[fcol].le(float(fr.name))]
for t in fr.data:
t.update(x=df_[xcol].values, y=df_[ycol].values)
fig

Related

How to force display of x- and y-axis for each subplot in plotly.express

I want to plot a histogram with row and colum facets using plotly.express.histogram() where each subplot gets its own x- and y-axis (for better readability). When looking at the documentation (e.g. go to section "Histogram Facet Grids") I can see a lot of examples where the x- and y-axes are repeated. But in my case, this somehow is not done automatically.
import numpy as np
import pandas as pd
import plotly.express as px
# create a dummy dataframe with lots of variables
rng = np.random.default_rng(42)
n_vars = 3
n_samples = 10
random_vars = [rng.normal(size=n_samples) for v in range(n_vars)]
m = np.vstack(random_vars).T
columns = pd.MultiIndex.from_tuples([('a','b'),('a','c'),('b','c')],names=['src','tgt'])
df = pd.DataFrame(m,columns=columns)
# convert to long format
df_long = df.melt()
# plot with plotly
fig = px.histogram(df_long,x='value',facet_row='src',facet_col='tgt')
fig.update_layout(yaxis={'side': 'left'})
fig.show()
which gives me:
How do I post-hoc configure the figure so that the x- and y-axis are shown for each subplot?
All you need to do is to customize each y and x axis by:
fig.for_each_yaxis(lambda y: y.update(showticklabels=True,matches=None))
fig.for_each_xaxis(lambda x: x.update(showticklabels=True,matches=None))
Output

Visualize a 408x408 numpy array as a heatmap

Hello I want to visualize the sandbox game map. I have collected the data from API and now I want to create a heatmap kind of visualization, where the color changes depending on how many times the land's been sold. I'm looking for a Python tool / GUI that will let me visualize a 408x408 numpy array. I've tried the seaborn heatmap, but it doesn't look clean (see image), even If I try to set figsize to (200, 200) it's not big enough for my needs. I want to have a visualization on potentially whole screen, where each land is big enough so that I can write something on it (potentially price). Better option would be to have a big map with sliders.
Perhaps it's possible to do what I want using Seaborn's heatmap, but I'm not very familiar with it.
Here's the code I used for visualization:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
arr = np.random.rand(408, 408)
x_labels = list(range(-204, 204))
y_labels = list(reversed(range(-204, 204)))
fig, ax = plt.subplots(figsize=(100, 100))
sns.heatmap(arr, square=True, xticklabels=x_labels, yticklabels=y_labels, ax=ax)
ax.tick_params(axis="both", labelsize=40)
Visualizing such large data with seaborn or Matplotlib will be difficult.
For that, we can use Plotly and the dash python library. So, we can add a slider to view some portion of data at a time.
I have used these two libraries.
import plotly.express as px
from dash import Dash, dcc, html, Input, Output
import numpy as np
import pandas as pd
#creating data
arr = np.random.rand(408, 408)
x_labels = list(range(-204, 204))
y_labels = list(reversed(range(-204, 204)))
#Converted to dataframe
df_data = pd.DataFrame(arr,index =y_labels, columns = [x_labels] )
app = Dash(__name__)
#How many items to show at a time
show_item_limit = 20
app.layout = html.Div([
html.H4('Range'),
dcc.Graph(id="graph"),
html.P("Select range"),
dcc.Slider(
min = 0,
max = 408-show_item_limit,
step = show_item_limit,
value = 0,
id= 'my-slider'
),
])
#app.callback(
Output("graph", "figure"),
Input("my-slider", "value"))
def filter_heatmap(selected_value):
# Selected value will be passed from Slider
df = df_data # replace with your own data source
#We can filter the data here
filtered_df = df_data.iloc[selected_value:selected_value+show_item_limit,range(selected_value,selected_value+show_item_limit)]
#Update using plotly
fig = px.imshow(filtered_df,
text_auto=True,
labels=dict(x="X-range", y="y-range"),
x = filtered_df.columns,
y = filtered_df.index
)
return fig
app.run_server(debug=True)
See the output image: Output from code

How to shorten and show only a part of text in plotly express axis?

I'm trying to output a graph that has ids on its x-axis and numbers on its y. Now I'm having difficulty seeing the graph itself as the ids are too long. I don't want to remove the whole ids and I just need to have for example the last few letters of each. Does anyone know if Plotly express has anything like using a regex for the labels?
To shorten the tick labels of your x-axis, you could either change the id's of your column beforehand by changing the dataframe, or you could use .update_layout() to change your tick labels afterwards.
See also: https://plotly.com/python/tick-formatting/
This question + answer is related: Plotly: How to set custom xticks
Example code:
import uuid
import numpy as np
import pandas as pd
import plotly.express as px
# generating some sample data and dataframe
length = 4
data = {
'colA': [str(uuid.uuid4()) for i in range(length)],
'colB': np.random.normal(size=length)
}
df = pd.DataFrame(data)
# create scatter plot
fig = px.scatter(data_frame=df, x='colA', y='colB', width=600, height=400)
# overwrite tick labels
fig.update_layout(
xaxis = {
'tickmode': 'array',
'tickvals': list(range(length)),
'ticktext': df['colA'].str.slice(-6).tolist(),
}
)
Resulting plot:

Python Plotly: Percentage Axis Formatter

I want to create a diagram from a pandas dataframe where the axes ticks should be percentages.
With matplotlib there is a nice axes formatter which automatically calculates the percentage ticks based on the given maximum value:
Example:
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame( { 'images': np.arange(0, 355, 5) } ) # 70 items in total, max is 350
ax = df.plot()
ax.yaxis.set_major_formatter(pltticker.PercentFormatter(xmax=350))
loc = pltticker.MultipleLocator(base=50) # locator puts ticks at regular intervals
ax.yaxis.set_major_locator(loc)
Since the usage of matplotlib is rather tedious, I want to do the same with Plotly. I only found the option to format the tick labels as percentages - but no 'auto formatter' who calculates the ticks and percentages for me. Is there a way to use automatic percentage ticks or do I have to calculate them everytime by hand (urgh)?
import plotly.express as px
import pandas as pd
fig = px.line(df, x=df.index, y=df.images, labels={'index':'num of users', '0':'num of img'})
fig.layout.yaxis.tickformat = ',.0%' # does not help
fig.show()
Thank you for any hints.
I'm not sure there's an axes option for percent, BUT it's relatively easy to get there by dividing y by it's max, y = df.y/df.y.max(). These types calculations, performed right inside the plot call, are really handy and I use them all of the time.
NOTE: if you have the possibility of negative values it does get more complicated (and ugly). Something like y=(df.y-df.y.min())/(df.y.max()-df.y.min()) may be necessary and a more general solution.
Full example:
import plotly.express as px
import pandas as pd
data = {'x': [0, 1, 2, 3, 4], 'y': [0, 1, 4, 9, 16]}
df = pd.DataFrame.from_dict(data)
fig = px.line(df, x=df.x, y=df.y/df.y.max())
#or# fig = px.line(df, x=df.x, y=(df.y-df.y.min())/(df.y.max()-df.y.min()))
fig.layout.yaxis.tickformat = ',.0%'
fig.show()

Including time tags on (X,Y,Z) coordinate plots [duplicate]

This question already has answers here:
Matplotlib: Annotating a 3D scatter plot
(7 answers)
Closed 3 years ago.
I have a dataframe flight data with X, Y, and Z location coordinates as well as time. I would like to create a 3-D plot where I can either:
1) Hover over each scatter point and have it display the X, Y, Z and Time at that point
OR
2) Add annotations to specific points. For instance, adding annotations for all points where Time > 900 and X < 500.
I am also open to any other methods that could give similar visualizations. As of now, I use a colorbar to show the increase of time during the trajectory, but I need to give a more detailed visualization.
EDIT: To be clear, the main problem I am trying to solve is how to annotate each data point with all of the information in each row of the dataframe (i.e. X,Y,Z, and Time).
import numpy as np
import pandas as pd
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
data = pd.DataFrame({"X": np.linspace(0,500,1001),
"Y": np.linspace(100,1000,1001),
"Z": np.linspace(0,100,1001),
"Time": np.linspace(0,1000,1001)})
fig = plt.figure()
ax = plt.axes(projection = "3d")
img = ax.scatter(data.X, data.Y, data.Z, c = data.Time, cmap = "Greens")
fig.colorbar(img)
plt.show()
For the hover data, you could do it with plotly. As of recent versions, you can use plotly.express, which is bundled into plotly:
import pandas as pd
import numpy as np
import plotly.express as px
data = pd.DataFrame({"X": np.linspace(0,500,1001),
"Y": np.linspace(100,1000,1001),
"Z": np.linspace(0,100,1001),
"Time": np.linspace(0,1000,1001)})
fig = px.scatter_3d(data, x = "X", y = "Y", z = "Z", hover_data = ["Time"])
# your plot will be rendered in your browser
fig.show()
If you're using an older version of plotly, or you don't want to use the express syntax, you can achieve the same with:
import plotly.graph_objects as go
import pandas as pd
import numpy as np
data = pd.DataFrame({"X": np.linspace(0,500,1001),
"Y": np.linspace(100,1000,1001),
"Z": np.linspace(0,100,1001),
"Time": np.linspace(0,1000,1001)})
fig = go.Figure(
data = [
go.Scatter3d(
x = data["X"],
y = data["Y"],
z = data["Z"],
mode = "markers"
),
hover_data = ["Time"]
]
)
fig.show()

Categories