migrated to bokeh

This commit is contained in:
Markus Rosenstihl 2025-03-27 22:22:35 +01:00
parent 3e24987f05
commit e6a841e09a
3 changed files with 66 additions and 46 deletions

View File

@ -1,9 +1,13 @@
<head> <head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link href=”https://cdn.pydata.org/bokeh/release/bokeh-3.7.1.min.css" rel=”stylesheet” type=”text/css”>
<link href=”https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.7.1.min.css" rel=”stylesheet” type=”text/css”>
</head> </head>
<body>
<div class="center"> <div class="center">
<h1>Isotopes</h1>
<table class="table w-auto table-responsive-sm table-striped table-hover table-bordered"> <table class="table w-auto table-responsive-sm table-striped table-hover table-bordered">
<caption> <caption>
Table downloaded from <a href="https://easyspin.org/documentation/isotopetable.html">easyspin.org</a> Table downloaded from <a href="https://easyspin.org/documentation/isotopetable.html">easyspin.org</a>
@ -29,17 +33,26 @@
{% endfor %} {% endfor %}
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{{ div| safe }}
<div> <div>
<img src="data:image/png;base64, {{ figure }}" alt="somealt" /> <script src="https://cdn.bokeh.org/bokeh/release/bokeh-3.7.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.7.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.7.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-api-3.7.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.7.1.min.js"></script>
{{ script| safe }}
</div> </div>
<a href="{% url 'home' %}">Go Back</a> <a href="{% url 'home' %}">Go Back</a>
</div> </div>
</body>
<style> <style>
.center { .center {
margin: auto; margin: auto;
@ -55,6 +68,8 @@
text-align: left; text-align: left;
} }
.table-striped {--bs-table-striped-bg: rgba(213, 217, 255, 0.7);} .table-striped {
--bs-table-striped-bg: rgba(213, 217, 255, 0.7);
}
</style> </style>

View File

@ -4,20 +4,18 @@ import base64
from django.shortcuts import render from django.shortcuts import render
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
import re import re
import numpy as np
import matplotlib
from setuptools.command.rotate import rotate
matplotlib.use('Agg') from bokeh.plotting import figure as bokehfig
from matplotlib.patches import Wedge, FancyArrowPatch from bokeh.embed import components
import matplotlib.pyplot as plt from bokeh.models import Label, Node, MathML
from isotopapp.models import Isotope from isotopapp.models import Isotope
# Create your views here. # Create your views here.
def home(request): def home(request):
isotopes = [i for i in Isotope.objects.all() if (i.gamma != 0 or i.stable)] isotopes = [i for i in Isotope.objects.all() if (i.gamma != 0 or i.stable)]
return render(request, 'home.html', {'isotopes': [[f"{i.n_nucleons}{i.symbol}", mark_safe(f"<sup>{i.n_nucleons}</sup>{i.symbol}")] for i in isotopes]}) return render(request, 'home.html', {'isotopes': [[f"{i.n_nucleons}{i.symbol}", mark_safe(f"<sup>{i.n_nucleons}</sup>{i.symbol}")] for i in isotopes],})
def extract_isotope_parts(isotope_str): def extract_isotope_parts(isotope_str):
"""Extracts the number and element from an isotope string (e.g., '23Na').""" """Extracts the number and element from an isotope string (e.g., '23Na')."""
@ -49,7 +47,9 @@ def result(request):
field_T = freq / isotope1.gamma field_T = freq / isotope1.gamma
figure=None script = None
div = None
print(request.GET) print(request.GET)
if request.GET.get('range_search') == "": if request.GET.get('range_search') == "":
close_isotopes = [isotope_info(isotope1, field_T)] close_isotopes = [isotope_info(isotope1, field_T)]
@ -65,24 +65,14 @@ def result(request):
ans = sorted(close_isotopes, key=lambda x: -float(x[3])) ans = sorted(close_isotopes, key=lambda x: -float(x[3]))
elif request.GET.get('gradient_search') == "": elif request.GET.get('gradient_search') == "":
fig, ax = plt.subplots(1, 1)
theta1, theta2 = 0, 360
radius = 2.5
center = (0, 0)
w = Wedge(center, radius, theta1, theta2, fc='#D5D9FFB2', edgecolor='black')
w_upper = Wedge((0,2.5), radius, theta1, theta2, fc='#D5D9FF42', edgecolor='black')
w_lower = Wedge((0,-2.5), radius, theta1, theta2, fc='#D5D9FF42', edgecolor='black')
ax.set_xlim([-5.5, 5.5])
ax.set_ylim([-5.5, 5.5])
ax.grid(True)
ax.add_patch(w_upper)
ax.add_patch(w_lower)
ax.add_patch(w)
sample_diameter = 5e-3 sample_diameter = 5e-3
gradient = float(request.GET.get('gradient')) gradient = float(request.GET.get('gradient'))
# create a plot (bokeh)
plot = bokehfig(outer_width=400, outer_height=400, match_aspect=True)
plot.ellipse(x=[0], y=[0], width=5, height=5, color="#D5D9FF", alpha=0.8, line_width=1, line_color="black")
plot.ellipse(x=[0], y= [2.5], width=5, height=5, color="#D5D9FF", alpha=0.4, line_width=1, line_color="black")
plot.ellipse(x=[0], y=[-2.5], width=5, height=5, color="#D5D9FF", alpha=0.4, line_width=1, line_color="black")
close_isotopes = [] close_isotopes = []
for isotope in Isotope.objects.all(): for isotope in Isotope.objects.all():
@ -93,22 +83,36 @@ def result(request):
i_info = isotope_info(isotope, field_T) i_info = isotope_info(isotope, field_T)
#i_info[3] = f"{z*1e3:.1f} mm" #i_info[3] = f"{z*1e3:.1f} mm"
close_isotopes.append(i_info) close_isotopes.append(i_info)
mathml = f"""
<math>
<msup>
{isotope.n_nucleons}
</msup>
{isotope.symbol}
</math>
"""
plot.rect(x=[0], y=[z*1e3], width=5, height=0.2, color="black", alpha=0.6)
label = Label(x=2.6, y=z*1e3, text=f"{isotope.n_nucleons}{isotope.symbol}", text_baseline="middle", text_align="left", text_font_size="16pt")
#label = Label(x=2.6, y=z*1e3, text=MathML(mathml), text_baseline="middle", text_align="left", text_font_size="16pt")
plot.add_layout(label)
arr = FancyArrowPatch((-2.5,z*1e3), (2.5, z*1e3), frame_left = Node(target="frame", symbol="left", offset=5)
arrowstyle='-', mutation_scale=20, linewidth=2) frame_bottom = Node(target="frame", symbol="bottom", offset=-5)
ax.add_patch(arr) citation = Label(
ax.annotate(f"{isotope.n_nucleons}{isotope.symbol}", (1.1, 0), xycoords=arr, ha='left', va='center',fontsize=8) x=frame_left,
ax.annotate(f"{isotope1.n_nucleons}{isotope1.symbol}: {freq:.1f}MHz\ng={gradient:.1f}T/m", y=frame_bottom,
(0.91, -0.45), xycoords=w, anchor="bottom_left",
ha='left', va='center',fontsize=11) #text=MathML(text=f"<math><msup>{isotope1.n_nucleons}</msup>{isotope1.symbol}: {freq:.1f} MHz\ng={gradient:.1f} T/m\n5 mm sample dia.</math>"),
text=f"{isotope1.n_nucleons}{isotope1.symbol}: {freq:.1f} MHz\ng={gradient:.1f} T/m\n5 mm sample dia.",
#text=MathML("<math>tewt</math>"),
padding=10,
border_radius=5,
border_line_color="black", background_fill_color="white",
)
plot.add_layout(citation)
ax.set_aspect('equal') # boke plot
ax.set_ylabel('z (mm)') script, div = components(plot)
buf = BytesIO()
plt.savefig(buf, format='png', dpi=120)
figure = base64.b64encode(buf.getvalue()).decode('utf-8').replace('\n', '')
buf.close()
ans = sorted(close_isotopes, key=lambda x: float(x[3])) ans = sorted(close_isotopes, key=lambda x: float(x[3]))
elif request.GET.get('transform') == "": elif request.GET.get('transform') == "":
@ -118,4 +122,4 @@ def result(request):
ans = [isotope_info(isotope2, field_T)] ans = [isotope_info(isotope2, field_T)]
else: else:
ans = [] ans = []
return render(request, 'result.html', {'ans': ans, 'figure': figure}) return render(request, 'result.html', {'ans': ans, 'script': script, 'div': div})

View File

@ -1,2 +1,3 @@
Django==5.1.6 Django==5.1.6
matplotlib==3.10.1 #matplotlib==3.10.1
bokeh==3.7.1