Creating a Dashboard of Graphs in Python - python

using matplotlib in Jupyter Notebook, I have already written code to produce a number of different graphs (example code below used to create some of my graphs). I would like to put all of these graphs into a dashboard. Is there a preferred method for my instance where I already have the graph produced and just want to plug it in to a dashboard template?
It seems like there are a number of different options (bokeh and plotly).
# multiple line plots
plt.plot( 'Week', 'ESI_1_2_3', data=SZ_ED_TOT, marker='o', color='blue', linewidth=2)
plt.plot( 'Week', 'ESI_4_5', data=SZ_ED_TOT, marker='o', color='red', linewidth=2)
plt.ylabel('Patient Count')
plt.xlabel('Week')
plt.xticks(rotation = 90)
plt.title('SZ Acuity Counts')
plt.gcf().set_size_inches(20, 8)
plt.legend()
plt.show()
# multiple line plots
plt.plot( 'Week', '%_1_2_3', data=UMC_ED_TOT, marker='o', color='blue', linewidth=2)
plt.plot( 'Week', '%_4_5', data=UMC_ED_TOT, marker='o', color='red', linewidth=2)
plt.ylabel('% of Patients')
plt.xlabel('Week')
plt.xticks(rotation = 90)
plt.title('UMC Acuity % Of Total Patients')
plt.gcf().set_size_inches(20, 8)
plt.legend()
plt.show()
#dual Y axis graph
ax = UMC_Cobmined.plot.bar(x='Week', y='Total', rot=90,color=(0.2, 0.4, 0.6, 0.6))
ax.set_xlabel('Week')
ax.set_ylabel('Total Volume')
ax2 = ax.twinx()
ax2.plot(ax.get_xticks(),
UMC_Cobmined[['%_ESI_3','%_ESI_4','%_ESI_5']].values,
linestyle='-',
marker='o', linewidth=2.0)
ax2.set_ylabel('% LWBS By Acuity')
ax2.legend(["%_ESI_3", "%_ESI_4","%_ESI_5"]);
plt.title('UMC LWBS Acuity % by Volume')
plt.gcf().set_size_inches(20, 8)
plt.show()
Ideal example of what I would like my dashboard to look like:

You can achieve this by using a grid in matplotlib:
import matplotlib.pytplot as plt
fig = plt.figure()
grid = fig.add_gridspec(NUMBER_OF_GRID_COLUMNS, NUMBER_OF_GRID_ROWS)
and then add each plot to an axis:
ax1 = fig.add_subplot(grid[0, 0])
# add plot to ax1
ax1.plot(x,y)
ax1.title("Plot on ax1")
ax2 = fig.add_subplot(grid[1,0])
# add plot to ax2
ax2.plot(x,y)
ax2.title("Plot on ax2")
plt.show()
and so on

Related

Adjusting legend layout for multiple legends associated to one Python plot?

I am creating a Python plot from a dataframe with 3 y-axes. For each y-axis, there are multiple y-values I want to plot. All data sets for the y-axes are plotted against a shared Date x-axis.
The code looks as follows:
df = pd.read_excel (r'test.xlsx', sheet_name='test', engine='openpyxl')
fig, ax = plt.subplots()
ax3 = ax.twinx()
rspine = ax3.spines['right']
rspine.set_position(('axes', 1.15))
ax3.set_frame_on(True)
ax3.patch.set_visible(False)
fig.subplots_adjust(right=0.7)
ax.plot(df['Date'], df['Gas1'], label="Gas1", color='g')
ax.plot(df['Date'], df['Gas2'], label="Gas2", color='b')
ax.plot(df['Date'], df['Gas3'], label="Gas3", marker="o", markersize=2, color='r')
ax.set_xlabel("Date")
ax.set_ylabel("Gas Rate")
ax2 = ax.twinx()
ax2.plot(df['Date'], df['Water1'], label="Water1", color='k')
ax2.plot(df['Date'], df['Water2'], label="Water2", color='y')
ax2.set_ylabel("Water")
ax3.plot(df['Date'], df['Pressure1'], label="Pressure1")
ax3.plot(df['Date'], df['Pressure2'], label="Pressure2")
ax3.set_ylabel("Pressure")
ax.legend()
ax2.legend()
ax3.legend()
plt.show()
The problem I am having is that I want the legends to be outside of the plot, preferably on the right-hand side after the 2nd y-axis. Is this possible? Right now the legends are just overlayed on the plot and not fully visible. I have tried using bbox_to_anchor and loc functions but had no luck. Thank you!
ax.get_legend_handles_labels() collects all the legend handles and their labels. Combining those for each of the axes, a new legend can be created.
bbox_to_anchor= sets an anchor point for the legend, using axes coordinates. loc= needs to be set, to tell which point of the legend's box will get fixed by the anchor.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame({'Date': pd.date_range('20210401', periods=30, freq='D'),
'Gas1': np.random.randn(30).cumsum(),
'Gas2': np.random.randn(30).cumsum(),
'Gas3': np.random.randn(30).cumsum(),
'Water1': np.random.randn(30).cumsum(),
'Water2': np.random.randn(30).cumsum(),
'Pressure1': np.random.randn(30).cumsum(),
'Pressure2': np.random.randn(30).cumsum()})
fig, ax = plt.subplots()
ax3 = ax.twinx()
rspine = ax3.spines['right']
rspine.set_position(('axes', 1.15))
ax3.set_frame_on(True)
ax3.patch.set_visible(False)
fig.subplots_adjust(right=0.7)
ax.plot(df['Date'], df['Gas1'], label="Gas1", color='g')
ax.plot(df['Date'], df['Gas2'], label="Gas2", color='b')
ax.plot(df['Date'], df['Gas3'], label="Gas3", marker="o", markersize=2, color='r')
ax.set_ylabel("Gas Rate")
plt.setp(ax.get_xticklabels(), rotation=45, ha='right')
ax2 = ax.twinx()
ax2.plot(df['Date'], df['Water1'], label="Water1", color='k')
ax2.plot(df['Date'], df['Water2'], label="Water2", color='y')
ax2.set_ylabel("Water")
ax3.plot(df['Date'], df['Pressure1'], label="Pressure1")
ax3.plot(df['Date'], df['Pressure2'], label="Pressure2")
ax3.set_ylabel("Pressure")
handles1, labels1 = ax.get_legend_handles_labels()
handles2, labels2 = ax2.get_legend_handles_labels()
handles3, labels3 = ax3.get_legend_handles_labels()
ax.legend(handles=handles1 + handles2 + handles3,
labels=labels1 + labels2 + labels3,
bbox_to_anchor=(1.28, 1.02), loc='upper left')
plt.tight_layout()
plt.show()

For scatterplot with matplotlib how to include in the legend gradient for dot size and colour?

I create two scatterplots with matplotlib in python with this code, the data for the code is here:
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
fig = plt.figure(figsize=(20,12))
ax1 = fig.add_subplot(111)
ax3 = ax1.twinx()
norm = Normalize(vmin=0.95*min(arr), vmax=1.05*max(arr))
ax1.scatter(x, y1, s=20, c=arr, cmap='Blues_r', norm=norm, marker='x', label='bla1')
ax3.scatter(x, y2, s=(20*(1.1-arr))**3.5, c=arr, cmap='Reds_r', norm=norm, marker='^', label='bla1')
The created fig. looks like this:
So, the dot size (in ax3) and the dot colour (in ax1 and ax3) are taken from arrays containing floats with all kinds of values in the range [0,1]. My question: How do I create a legend that displays the corresponding y-values for, let's say 5 different dot sizes and 5 different colour nuances?
I would like the legend to look like in the figure below (source here), but with the colour bar and size bar put into a single legend, if possible. Thanks for suggestions and code!
# using your data in dataframe df
# create s2
df['s2'] = (20*(1.1-df.arr))**3.5
fig = plt.figure(figsize=(20,12))
ax1 = fig.add_subplot(111)
ax3 = ax1.twinx()
norm = Normalize(vmin=0.95*min(df.arr), vmax=1.05*max(df.arr))
p1 = ax1.scatter(df.x, df.y1, s=20, c=df.arr, cmap='Blues_r', norm=norm, marker='x')
fig.colorbar(p1, label='arr')
p2 = ax3.scatter(df.x, df.y2, s=df.s2, c=df.arr, cmap='Reds_r', norm=norm, marker='^')
fig.colorbar(p2, label='arr')
# create the size legend for red
for x in [15, 80, 150]:
plt.scatter([], [], c='r', alpha=1, s=x, label=str(x), marker='^')
plt.legend(loc='upper center', bbox_to_anchor=(1.23, 1), ncol=1, fancybox=True, shadow=True, title='s2')
plt.show()
There's no legend for p1 because the size is static.
I think this would be better as two separate plots
I used Customizing Plot Legends: Legend for Size of Points
Separate
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(20, 10))
norm = Normalize(vmin=0.95*min(df.arr), vmax=1.05*max(df.arr))
p1 = ax1.scatter(df.x, df.y1, s=20, c=df.arr, cmap='Blues_r', norm=norm, marker='x')
fig.colorbar(p1, ax=ax1, label='arr')
p2 = ax2.scatter(df.x, df.y2, s=df.s2, c=df.arr, cmap='Reds_r', norm=norm, marker='^')
fig.colorbar(p2, ax=ax2, label='arr')
# create the size legend for red
for x in [15, 80, 150]:
plt.scatter([], [], c='r', alpha=1, s=x, label=str(x), marker='^')
plt.legend(loc='upper center', bbox_to_anchor=(1.2, 1), ncol=1, fancybox=True, shadow=True, title='s2')
plt.show()

Scatter plot with markers changing size according to number of represented points

I'm plotting a simple scatter plot:
It represents my data correctly, however there is many datapoints with coordinates (1.00,1.00) and in the plot, they appear under a single marker (top right corner). I'd like to have a functionality that changes the size of every marker according to the number of points it is representing. Will appreciate any help. Here's my code:
def saveScatter(figureTitle, xFeature, yFeature, xTitle, yTitle):
''' save a scatter plot of xFeatures vs yFeatures '''
fig = plt.figure(figsize=(8, 6), dpi=300)
ax = fig.add_subplot(111)
ax.scatter(dfModuleCPositives[names[xFeature]][:], dfModuleCPositives[names[yFeature]][:], c='r', marker='x', alpha=1, label='Module C Positives')
ax.scatter(dfModuleCNegatives[names[xFeature]][:], dfModuleCNegatives[names[yFeature]][:], c='g', alpha=0.5, label='Module C Negatives')
ax.scatter(dfModuleDPositives[names[xFeature]][:], dfModuleDPositives[names[yFeature]][:], c='k', marker='x', alpha=1, label='Module D Positives')
ax.scatter(dfModuleDNegatives[names[xFeature]][:], dfModuleDNegatives[names[yFeature]][:], c='b', alpha=0.5, label='Module D Negatives')
ax.set_xlabel(xTitle, fontsize=10)
ax.set_ylabel(yTitle, fontsize=10)
ax.set_title(figureTitle)
ax.grid(True)
ax.legend(loc="lower right")
fig.tight_layout()
plt.show()
return ax

Pyplot refuses to show grid

I have a python script that has 3 functions that plot data. 2 of them show gridlines by using ax.grid(b=True). One however, doesn't. Even after I spammed ax.grid(b=True) all over the place... I must be doing something wrong, but what?
def plotMSEProgress(times, bestScores, scores, xsplit=0, window=1):
plot, ax = plt.subplots(figsize=(20,10), num=1)
ax.grid(b=True, which='both')
# plot = plt.figure(window)
plt.ion()
plt.minorticks_on()
ax.grid(b=True, which='both')
plt.show()
plt.clf()
if xsplit:
plt.axvline(x=xsplit, color='g')
plot = plt.plot_date(times, bestScores, '-', label="best score")
plot = plt.setp(plot, color='y', linewidth=1.0)
plot = plt.plot_date(times, scores, '-', label="score")
plot = plt.setp(plot, color='b', linewidth=1.0)
ax.grid(b=True, which='both')
plt.xlabel('time')
plt.ylabel('MSE')
plt.suptitle('MSE over time', fontsize=16)
plt.legend()
ax.grid(b=True, which='both')
plt.draw()
ax.grid(b=True, which='both')
plt.pause(0.001)
ax.grid(b=True, which='both')
plt.plot()
ax.grid(b=True, which='both')
Maybe it has something to do with plt.ion() ? Because I don't have that in the othe plotting functions that do show the grid.
I already tried this and this by adding the plt.minorticks_on(), but to no avail sadly.
Is there something obvious I'm missing? Or is there some other hidden incompatibility?
Screenshot of plot as requested:
Add in a call to plt.grid() inside your function, and remove extraneous code:
import matplotlib.pyplot as plt
import datetime
def plotMSEProgress(times, bestScores, scores, xsplit=0, window=1):
plot, ax = plt.subplots(figsize=(20,10), num=1)
plt.ion()
plt.clf()
if xsplit:
plt.axvline(x=xsplit, color='g')
plot = plt.plot_date(times, bestScores, '-', label="best score")
plot = plt.setp(plot, color='y', linewidth=1.0)
plot = plt.plot_date(times, scores, '-', label="score")
plot = plt.setp(plot, color='b', linewidth=1.0)
plt.minorticks_on()
plt.grid(which='major')
plt.grid(which='minor', linestyle = ':')
plt.xlabel('time')
plt.ylabel('MSE')
plt.suptitle('MSE over time', fontsize=16)
plt.legend(loc=2)
plt.draw()
plt.pause(0.001)
# Generate example data
base = datetime.datetime.today()
times = [base + datetime.timedelta(seconds=x) for x in range(0, 100)]
scores = np.random.rand(len(times))*30
bestScores = np.random.rand(len(times))*5
# Generate plot dynamically
for i in range(len(times)):
plotMSEProgress(times[0:i], bestScores[0:i], scores[0:i], xsplit=0, window=1)
This code generates a plot and dynamically updates it, all while showing the gridlines the whole time.
I think you have some unnecessary codes, which creates multiple plots. The first plot you had is empty but with grids and the later plots contain the data, but not the grids.
Try the code below. I commented some of your scripts and made it work.
def plotMSEProgress(times, bestScores, scores, xsplit=0, window=1):
plot, ax = plt.subplots(figsize=(20,10), num=1)
ax.grid(b=True, which='both')
# plot = plt.figure(window)
plt.ion()
plt.minorticks_on()
ax.grid(b=True, which='both')
# plt.show()
# plt.clf()
if xsplit:
plt.axvline(x=xsplit, color='g')
plot = plt.plot(times, bestScores, '-', label="best score") # you can change it back to plot_date
plot = plt.setp(plot, color='y', linewidth=1.0)
plot = plt.plot(times, scores, '-', label="score") # you can change it back to plot_date
plot = plt.setp(plot, color='b', linewidth=1.0)
ax.grid(b=True, which='both')
plt.xlabel('time')
plt.ylabel('MSE')
plt.suptitle('MSE over time', fontsize=16)
plt.legend()
ax.grid(b=True, which='both')
plt.draw()
ax.grid(b=True, which='both')
plt.pause(0.001)
ax.grid(b=True, which='both')
# plt.plot()
ax.grid(b=True, which='both')
times = list(range(0,100))
bestScores = list(range(100,200))
scores = list(range(150,250))
xsplit=0
window=1
plotMSEProgress(times, bestScores, scores, xsplit=0, window=1)

Python: Suplots with secondary-axis

I wrote the following code below to do the following graph:
fig, ax = plt.subplots(figsize=(8, 6))
ax.patch.set_facecolor('white')
ax.plot(df.index, df.X1.values, 'b',
label='NMA', linewidth=1.5)
ax.set_ylabel('Index')
ax2 = ax.twinx()
ax2.plot(df.index, df.Y.values, 'r--',
label='Rate', linewidth=1.5)
ax2.set_ylabel('Rate')
lines = ax.get_lines() + ax2.get_lines()
lgd = ax.legend(lines, [line.get_label() for line in lines],
loc='lower center', ncol=2, bbox_to_anchor=(0.5, -0.15),
frameon=False)
ax.set_title('Economic Rate and Index',
weight='bold')
for i in range(5):
plt.axvspan(Dates['Peak'][i], Dates['Trough'][i],
facecolor='grey', alpha=0.5)
plt.grid(False)
plt.savefig('C:\\test.pdf',
bbox_extra_artists=(lgd,), bbox_inches='tight')
I am having a hard time to reproduce this figure in a subplot (2X2). The only thing I would change in each of the subplots is the blue line (X1 in df... for X2, X3...). How can I have a 2X2 subplot of the above graph? Of Course I would only keep one legend at the bottom of the subplots. Thanks for the help.
The data is here and the "Dates" to reproduce the gray bars here.
This is how you could create a 2x2 raster with twinx each:
import matplotlib.pyplot as plt
fig, ((ax1a, ax2a), (ax3a, ax4a)) = plt.subplots(2, 2)
ax1b = ax1a.twinx()
ax2b = ax2a.twinx()
ax3b = ax3a.twinx()
ax4b = ax4a.twinx()
ax1a.set_ylabel('ax1a')
ax2a.set_ylabel('ax2a')
ax3a.set_ylabel('ax3a')
ax4a.set_ylabel('ax4a')
ax1b.set_ylabel('ax1b')
ax2b.set_ylabel('ax2b')
ax3b.set_ylabel('ax3b')
ax4b.set_ylabel('ax4b')
plt.tight_layout()
plt.show()
Result:

Categories