Bokeh layout resize multiple plots - layout

Using the example from https://github.com/bokeh/bokeh/blob/branch-2.4/examples/plotting/file/sizing_mode.py
I added a second plot. The sizing mode only seem to apply to the first plot.
Is there a trick to get both plots to respond to resize? Thanks
from bokeh.core.enums import SizingMode
from bokeh.layouts import column
from bokeh.models import Select
from bokeh.plotting import figure, output_file, show
from bokeh.sampledata.iris import flowers as df
colormap = {'setosa': 'red', 'versicolor': 'green', 'virginica': 'blue'}
colors = [colormap[x] for x in df.species]
plot = figure(sizing_mode="fixed")
plot.circle(df.petal_length, df.petal_width, color=colors, alpha=0.2, size=10)
plot2 = figure(sizing_mode="fixed")
plot2.circle(df.petal_length, df.petal_width, color=colors, alpha=0.2, size=10)
select = Select(title="Sizing mode", value="fixed", options=list(SizingMode), width=300)
select.js_link('value', plot, 'sizing_mode')
layout = column(select, plot, plot2)
layout.sizing_mode = "stretch_both" # set separately to avoid also setting children
output_file("sizing_mode.html", title="sizing_mode.py example")
show(layout)

I spotted my error in that code. Should have done js_link on layout instead of just the first plot.
select.js_link('value', layout, 'sizing_mode')
this works fine. thank you.

Related

How to highlight current cursor values on X and Y axis in plotly?

I have a plotly chart and whenever I move cursor on it, I want to see corresponding X and Y values being highlighted. How can I achieve that? Below is sample image of how it should look.
(Not a very clear image, but on Y-axis you can see highlighted tickers)
Here's a sample code for a simple plotly plot
import datetime as dt
import panel as pn
import yfinance as yf
pn.extension()
# Data part
vix_tickers = ['AUDJPY=X']
df = yf.download(vix_tickers,
auto_adjust=True, #only download adjusted data
progress=False,
)
df = df[["Close"]]
# A Plot
import plotly.graph_objs as go
fig = go.Figure()
df.sort_index(ascending=True, inplace=True)
trace = go.Scatter(x=list(df.index), y=list(df.Close))
fig.add_trace(trace)
fig.update_layout(
dict(
title="Time series with range slider and selectors",
xaxis=dict(
rangeselector=dict(
buttons=list(
[
dict(count=1, label="1m", step="month", stepmode="backward"),
dict(count=6, label="6m", step="month", stepmode="backward"),
dict(count=1, label="YTD", step="year", stepmode="todate"),
dict(count=1, label="1y", step="year", stepmode="backward"),
dict(step="all"),
]
)
),
rangeslider=dict(visible=False),
type="date",
),
)
)
fig.show()

Is it possible to use matplotlib to include a subheading in legend that isnt a part of the graph?

I am using matplotlib to plot a pie chart. I have added a legend to the chart. However, i would like to add a "Total" to the legend, to sum up the values of all the other categories. Hence the value of "Total" would not be a part of the pie chart, and would only be shown in the legend. Is it possible for me to do that? Thank you.
You can create 2 legends. On the second one, you can create/manipulate symbol/text/title as you want. Here is a runnable code that you can try.
from matplotlib import pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.axis('equal')
langs = ['C', 'C++', 'Java', 'Python', 'PHP']
students = [23,17,35,29,12]
ax.pie(students, labels = langs,autopct='%1.2f%%')
# first legend
lgn = plt.legend()
ax = plt.gca().add_artist(lgn)
# second legend
gold_patch = mpatches.Patch(color='gold', label='Total= 9999') # use your description text here
second_legend = plt.legend(handles=[gold_patch], loc=1, \
bbox_to_anchor=(0.5, 0.35, 0.55, 0.35)) # adjust location of legend here
second_legend.set_frame_on(False) # use True/False as needed
second_legend.set_title("Other categories")
plt.show()
The output plot:

Using "hue" for a Seaborn visual: how to get legend in one graph?

I created a scatter plot in seaborn using seaborn.relplot, but am having trouble putting the legend all in one graph.
When I do this simple way, everything works fine:
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import seaborn as sns
df2 = df[df.ln_amt_000s < 700]
sns.relplot(x='ln_amt_000s', y='hud_med_fm_inc', hue='outcome', size='outcome', legend='brief', ax=ax, data=df2)
The result is a scatter plot as desired, with the legend on the right hand side.
However, when I try to generate a matplotlib figure and axes objects ahead of time to specify the figure dimensions I run into problems:
a4_dims = (10, 10) # generating a matplotlib figure and axes objects ahead of time to specify figure dimensions
df2 = df[df.ln_amt_000s < 700]
fig, ax = plt.subplots(figsize = a4_dims)
sns.relplot(x='ln_amt_000s', y='hud_med_fm_inc', hue='outcome', size='outcome', legend='brief', ax=ax, data=df2)
The result is two graphs -- one that has the scatter plots as expected but missing the legend, and another one below it that is all blank except for the legend on the right hand side.
How do I fix this such? My desired result is one graph where I can specify the figure dimensions and have the legend at the bottom in two rows, below the x-axis (if that is too difficult, or not supported, then the default legend position to the right on the same graph would work too)? I know the problem lies with "ax=ax", and in the way I am specifying the dimensions as matplotlib figure, but I'd like to know specifically why this causes a problem so I can learn from this.
Thank you for your time.
The issue is that sns.relplot is a "Figure-level interface for drawing relational plots onto a FacetGrid" (see the API page). With a simple sns.scatterplot (the default type of plot used by sns.relplot), your code works (changed to use reproducible data):
df = pd.read_csv("https://vincentarelbundock.github.io/Rdatasets/csv/datasets/iris.csv", index_col=0)
fig, ax = plt.subplots(figsize = (5,5))
sns.scatterplot(x = 'Sepal.Length', y = 'Sepal.Width',
hue = 'Species', legend = 'brief',
ax=ax, data = df)
plt.show()
Further edits to legend
Seaborn's legends are a bit finicky. Some tweaks you may want to employ:
Remove the default seaborn title, which is actually a legend entry, by getting and slicing the handles and labels
Set a new title that is actually a title
Move the location and make use of bbox_to_anchor to move outside the plot area (note that the bbox parameters need some tweaking depending on your plot size)
Specify the number of columns
fig, ax = plt.subplots(figsize = (5,5))
sns.scatterplot(x = 'Sepal.Length', y = 'Sepal.Width',
hue = 'Species', legend = 'brief',
ax=ax, data = df)
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles=handles[1:], labels=labels[1:], loc=8,
ncol=2, bbox_to_anchor=[0.5,-.3,0,0])
plt.show()

Matplotlib bar plot with table formatting

I have added a table to the bottom of my plot, but there are a number of issues with it:
The right has too much padding.
The left has too little padding.
The bottom has no padding.
The cells are too small for the text within them.
The table is too close to the bottom of the plot.
The cells belonging to the row names are not colored to match those of the bars.
I'm going out of my mind fiddling with this. Can someone help me fix these issues?
Here is the code (Python 3):
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
# Set styles
plt.style.use(['seaborn-paper', 'seaborn-whitegrid'])
plt.style.use(['seaborn'])
sns.set(palette='colorblind')
matplotlib.rc("font", family="Times New Roman", size=12)
labels = ['n=1','n=2','n=3','n=4','n=5']
a = [98.8,98.8,98.8,98.8,98.8]
b = [98.6,97.8,97.0,96.2,95.4]
bar_width = 0.20
data = [a,b]
print(data)
colors = plt.cm.BuPu(np.linspace(0, 0.5, len(labels)))
columns = ('n=1', 'n=2', 'n=3', 'n=4', 'n=5')
index = np.arange(len(labels))
plt.bar(index, a, bar_width)
plt.bar(index+bar_width+.02, b, bar_width)
plt.table(cellText=data,
rowLabels=['a', 'b'],
rowColours=colors,
colLabels=columns,
loc='bottom')
plt.subplots_adjust(bottom=0.7)
plt.ylabel('Some y label which effect the bottom padding!')
plt.xticks([])
plt.title('Some title')
plt.show()
This is the output:
Update
This is working now, but in case someone else is having issues: Make sure you are not viewing your plots and the changes you make to them with IntelliJ SciView as it does not represent changes accurately and introduces some formatting issues!
I think you can fix the first problem by setting the bounding box when you make the table using bbox like this:
bbox=[0, 0.225, 1, 0.2]
where the parameters are [left, bottom, width, height].
For the second issue (the coloring), that is because the color array is not corresponding to the seaborn coloring. You can query the seaborn color palette with
sns.color_palette(palette='colorblind')
this will give you a list of the colors seaborn is using.
Check the modifications below:
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
# Set styles
plt.style.use(['seaborn-paper', 'seaborn-whitegrid'])
plt.style.use(['seaborn'])
sns.set(palette='colorblind')
matplotlib.rc("font", family="Times New Roman", size=12)
labels = ['n=1','n=2','n=3','n=4','n=5']
a = [98.8,98.8,98.8,98.8,98.8]
b = [98.6,97.8,97.0,96.2,95.4]
bar_width = 0.20
data = [a,b]
colors = sns.color_palette(palette='colorblind')
columns = ('n=1', 'n=2', 'n=3', 'n=4', 'n=5')
index = np.arange(len(labels))
fig = plt.figure(figsize=(12,9))
plt.bar(index, a, bar_width)
plt.bar(index+bar_width+.02, b, bar_width)
plt.table(cellText=data,
rowLabels=[' a ', ' b '],
rowColours=colors,
colLabels=columns,
loc='bottom',
bbox=[0, 0.225, 1, 0.2])
fig.subplots_adjust(bottom=0.1)
plt.ylabel('Some y label which effect the bottom padding!')
plt.xticks([])
plt.title('Some title')
plt.show()
I also changed the subplot adjustment to subplot_adjust(bottom=0.1) because it wasn't coming out right otherwise. Here is the output:

better piechart color scheme

I am trying to create a pie chart, as follows:
import matplotlib.pyplot as plt
import pandas as pd
# make a square figure and axes
plt.figure(1, figsize=(10,10))
plt.axes([0.01, 0.1, 0.6, 0.6])
# plt.style.use('fivethirtyeight')
# The slices will be ordered and plotted counter-clockwise.
labels = 'foo1', 'foo2', 'foo3', 'foo4'
fracs = pd.Series([10,30, 50,10],index=labels)
fracs.plot(kind='pie', labels=None, autopct='%1.0f%%')
plt.legend(bbox_to_anchor=(0.95, .9), loc=2, borderaxespad=0.,labels=labels)
plt.title('pie chart demo which should be center aligned not left', bbox={'facecolor':'0.8', 'pad':5})
plt.show()
Which is yeilding a piechart as:
But, I am facing two problem:
1) I dont like the color scheme. I would like a color scheme more inline with (I need 12 colors)
2) Titel is centered at the pie chart only. The legend is somehow out. I am trying to get the title centered over the chart and the legend.
Can someone kindly help?
I think that is a ggplot colorscheme that you are trying to emulate.
And your plt.axes command is what is displacing your chart to the left.
Try this:
import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.figure(1, figsize=(10,10))
labels = 'foo1', 'foo2', 'foo3', 'foo4'
sizes = [10,30, 50,10]
plt.pie(sizes, labels=labels)
plt.show()

Resources