loop matplotlib figure to html pages flask app

56 Views Asked by At

I've been struggling to insert a graph/chart into the html. I've tried a basic matplotlib chart (TEST FIG 1) using mpld3 to convert the figure to html. I've also tried to create a graph with mplfinance (TEST FIG 2). All of what I've tried so far has been unsuccessful, going on days now.

First chart I'm wanting to make, I'm trying to pull data for each ticker into a chart that corresponds with the correct ticker's ticker_page.html. Then I tried to make it even more simple, hence (TEST FIG 1)

I'm thinking my problem is really how to link the @app.route correctly. I am not wanting a .png or something static, since later when I understand the connection better I'll make the figures interactive with possible hyperlinks, scrolling features, etc.

For background info on how the app is set up so far, there is a /News page. On the News page there are names in a list. When you click on one of the names it takes you to the /ticker page, which displays the ticker_page.html correctly other than the charts I've tried to insert.

APP.PY:

from flask import Flask, render_template, request
from datetime import datetime
from itertools import groupby
import pipeline
import mpld3
import matplotlib.pyplot as plt
import pandas_datareader
import mplfinance as mpf

app = Flask(__name__)

# Read in the data from the CSV file
CSV_data = 'path'


with open(CSV_data, 'r', encoding='utf-8') as csvfile:
    reader = csv.DictReader(csvfile)
    articles = [row for row in reader]

# Get the list of unique tickers from the data
tickers = sorted(set(article['Ticker'] for article in articles))


def format_date(date_str):
    try:
        # Check if date string is in "DD-Mon-YY" format
        date_obj = datetime.strptime(date_str, "%d-%b-%y")
    except ValueError:
        # Check if date string is in "MM/DD/YYYY" format
        date_obj = datetime.strptime(date_str, "%m/%d/%Y")
    
    return date_obj.date().strftime("%m-%d-%Y")


def sort_articles(articles):
    try:
        return sorted(articles, key=lambda x: datetime.strptime(x["Date"], "%m-%d-%Y"), reverse=True)
    except (KeyError, ValueError):
        print("Houston, we have a problem")
        return articles


@app.route('/')
def index():
    # Your logic for the home page here
    # For example, you can set up a welcome message
    welcome_message = "Welcome!"
    return render_template('index.html', welcome_message=welcome_message)


@app.route('/news')
def urls():
    selected_tickers = request.args.getlist('ticker')

    # Filter the articles based on the selected tickers
    filtered_articles = [article for article in articles if not selected_tickers or article['Ticker'] in selected_tickers]

    # Generate a dictionary to map each ticker to its date, title, and link
    ticker_articles = {}
    for article in filtered_articles:
        ticker = article['Ticker']
        if ticker not in ticker_articles:
            ticker_articles[ticker] = []
        ticker_articles[ticker].append((article['Date'], article['Title'], article['Link']))

    # Render the 'urls.html' template with the necessary data
    return render_template('urls.html', tickers=tickers, filtered_articles=filtered_articles, ticker_articles=ticker_articles)




#TEST FIG 1
@app.route('/graph/<string:ticker>/')
def graph(ticker):
    fig, ax = plt.subplots(ticker)
    # Add some data to the plot
    ax.plot([1, 2, 3], [4, 5, 6])
    # Convert the Matplotlib figure to HTML
    html_graph = mpld3.fig_to_html(fig)
    return render_template('ticker_page.html', html_graph=html_graph)


#TEST FIG 2
@app.route('/pricegraph/<string:ticker>/')

def generate_price_chart(ticker):
    """Generates a price chart for the given ticker."""

    # Get the historical price data for the ticker
    df = mpf.DataReader(ticker, period="1d")

    # Create a Matplotlib figure
    fig = mpf.figure(figsize=(10, 6))

    # Add the price chart to the figure
    mpf.plot(df, type="candle", style="yahoo", fig=fig, ax=fig.add_subplot(111))

    # Convert the Matplotlib figure to HTML
    html = mpf.fig_to_html(fig)

    return html





@app.route('/ticker/<string:ticker>/')
def ticker_page(ticker):


    # Sample data for demonstration purposes
    ticker_data = {
        'ticker': ticker,
        'date': '2023-07-19',
        'article_name': 'Sample Article for ' + ticker,
        'article_url': 'https://example.com/' + ticker,
        #'chart': html_graph
    }



    # Render the 'ticker_page.html' template with the ticker data
    return render_template('ticker_page.html', ticker_data=ticker_data)#, html_graph=html_graph)#, html=html_pipeline)


if __name__ == '__main__':
    app.run(debug=True)

TICKER_PAGE.HTML




{% extends 'base.html' %}

{% block content %}
<title>{{ ticker_data.ticker }} Page - TITLE</title>
<head>

</head>

<body>
    

<div></div>
    <div id="data"><h1>{{ ticker_data.ticker }}</h1>
        <p>Date: {{ ticker_data.date }}</p>
    </div>

    <div id="pipeline">
        <h2>Pipeline Chart</h2>
        <div>
            {{html_graph}}
        </div>

        <div>
            <script>
                // Get the price chart HTML
                var html = "{{ html }}";
        
                // Render the price chart
                document.getElementById("pricegraph").innerHTML = html;
            </script>        </div>
    </div>

    <div id="news">
        <h2>Press Releases</h2>
        <p>Sample Article URL: 
            <a href="{{ ticker_data.article_url }}" target="_blank">{{ ticker_data.article_name }}</a>
        </p>
        <p>Sample Article: {{ ticker_data.article_name }}</p>

    </div>
</div>
</body>
{% endblock %}

I've been struggling to insert a graph/chart into the html. I've tried a basic matplotlib chart (TEST FIG 1) using mpld3 to convert the figure to html. I've also tried to create a graph with mplfinance (TEST FIG 2). All of what I've tried so far has been unsuccessful, going on days now.

I'm thinking my problem is really how to link the @app.route correctly. I am not wanting a .png or something static, since later when I understand the connection better I'll make the figures interactive with possible hyperlinks, scrolling features, etc.

For background info on how the app is set up so far, there is a /News page. On the News page there are names in a list. When you click on one of the names it takes you to the /ticker page, which displays the ticker_page.html correctly other than the charts I've tried to insert.

APP.PY:

from flask import Flask, render_template, request
from datetime import datetime
from itertools import groupby
import pipeline
import mpld3
import matplotlib.pyplot as plt
import pandas_datareader
import mplfinance as mpf

app = Flask(__name__)

# Read in the data from the CSV file
CSV_data = 'path'


with open(CSV_data, 'r', encoding='utf-8') as csvfile:
    reader = csv.DictReader(csvfile)
    articles = [row for row in reader]

# Get the list of unique tickers from the data
tickers = sorted(set(article['Ticker'] for article in articles))


def format_date(date_str):
    try:
        # Check if date string is in "DD-Mon-YY" format
        date_obj = datetime.strptime(date_str, "%d-%b-%y")
    except ValueError:
        # Check if date string is in "MM/DD/YYYY" format
        date_obj = datetime.strptime(date_str, "%m/%d/%Y")
    
    return date_obj.date().strftime("%m-%d-%Y")


def sort_articles(articles):
    try:
        return sorted(articles, key=lambda x: datetime.strptime(x["Date"], "%m-%d-%Y"), reverse=True)
    except (KeyError, ValueError):
        print("Houston, we have a problem")
        return articles


@app.route('/')
def index():
    # Your logic for the home page here
    # For example, you can set up a welcome message
    welcome_message = "Welcome!"
    return render_template('index.html', welcome_message=welcome_message)


@app.route('/news')
def urls():
    selected_tickers = request.args.getlist('ticker')

    # Filter the articles based on the selected tickers
    filtered_articles = [article for article in articles if not selected_tickers or article['Ticker'] in selected_tickers]

    # Generate a dictionary to map each ticker to its date, title, and link
    ticker_articles = {}
    for article in filtered_articles:
        ticker = article['Ticker']
        if ticker not in ticker_articles:
            ticker_articles[ticker] = []
        ticker_articles[ticker].append((article['Date'], article['Title'], article['Link']))

    # Render the 'urls.html' template with the necessary data
    return render_template('urls.html', tickers=tickers, filtered_articles=filtered_articles, ticker_articles=ticker_articles)




#TEST FIG 1
@app.route('/graph/<string:ticker>/')
def graph(ticker):
    fig, ax = plt.subplots(ticker)
    # Add some data to the plot
    ax.plot([1, 2, 3], [4, 5, 6])
    # Convert the Matplotlib figure to HTML
    html_graph = mpld3.fig_to_html(fig)
    return render_template('ticker_page.html', html_graph=html_graph)


#TEST FIG 2
@app.route('/pricegraph/<string:ticker>/')

def generate_price_chart(ticker):
    """Generates a price chart for the given ticker."""

    # Get the historical price data for the ticker
    df = mpf.DataReader(ticker, period="1d")

    # Create a Matplotlib figure
    fig = mpf.figure(figsize=(10, 6))

    # Add the price chart to the figure
    mpf.plot(df, type="candle", style="yahoo", fig=fig, ax=fig.add_subplot(111))

    # Convert the Matplotlib figure to HTML
    html = mpf.fig_to_html(fig)

    return html





@app.route('/ticker/<string:ticker>/')
def ticker_page(ticker):


    # Sample data for demonstration purposes
    ticker_data = {
        'ticker': ticker,
        'date': '2023-07-19',
        'article_name': 'Sample Article for ' + ticker,
        'article_url': 'https://example.com/' + ticker,
        #'chart': html_graph
    }



    # Render the 'ticker_page.html' template with the ticker data
    return render_template('ticker_page.html', ticker_data=ticker_data)#, html_graph=html_graph)#, html=html_pipeline)


if __name__ == '__main__':
    app.run(debug=True)

TICKER_PAGE.HTML




{% extends 'base.html' %}

{% block content %}
<title>{{ ticker_data.ticker }} Page - TITLE</title>
<head>

</head>

<body>
    

<div></div>
    <div id="data"><h1>{{ ticker_data.ticker }}</h1>
        <p>Date: {{ ticker_data.date }}</p>
    </div>

    <div id="pipeline">
        <h2>Pipeline Chart</h2>
        <div>
            {{html_graph}}
        </div>

        <div>
            <script>
                // Get the price chart HTML
                var html = "{{ html }}";
        
                // Render the price chart
                document.getElementById("pricegraph").innerHTML = html;
            </script>        </div>
    </div>

    <div id="news">
        <h2>Press Releases</h2>
        <p>Sample Article URL: 
            <a href="{{ ticker_data.article_url }}" target="_blank">{{ ticker_data.article_name }}</a>
        </p>
        <p>Sample Article: {{ ticker_data.article_name }}</p>

    </div>
</div>
</body>
{% endblock %}
1

There are 1 best solutions below

0
Ash Cash On

I figured out partially what I'm going for, but enough to answer the base of this question. I shouldn't have been using matplotlib. I should have been using chart.js. I don't know how to call from app.py yet, but now I've found I can insert the chart directly into the HTML.

Link to chart.js docs: https://www.chartjs.org/docs/latest/

ticker_page.html

<! -- This is the Tickers (looped) page -->



{% extends 'base.html' %}

{% block content %}
<title>{{ ticker_data.ticker }} Page - title</title>
<head>
    <style>
    h1, h2 {
        color: #006600;
    }
    h2 {
        font-size: 30px;
    }
    p {
        font-size: 18px;
    }
    #pipeline{height: 700px;}

    #chart_last_updated{text-align: right;}
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>


</head>

<body>

    
    

<div></div>
    <div id="data"><h1>{{ ticker_data.ticker }}</h1>
        <p> </p>
    </div>

    <div id="pipeline">
        <h2>Pipeline Chart</h2>
        
        <div>
            <div>
                <canvas id="myChart"></canvas>
            </div id=chart>
              
            <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
              
            <script>
                const ctx = document.getElementById('myChart');
              
                new Chart(ctx, {
                  type: 'bar',
                  data: {
                    labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
                    datasets: [{
                      label: 'Drug Phase',
                      data: [.5, 1, 2, 3, 4, 3],
                      borderWidth: 1
                    }]
                  },
                  options: {
                    indexAxis: 'y', // <-- MAKES CHART HBAR
                    responsive: true
                  }
                  });
            </script>
            <p id="chart_last_updated"> Chart Last Updated: {{ ticker_data.date }}</p>
            </div>  
        </div>

    
        <div>
            

        </div>
    </div>

    <div id="news">
        <h2>Press Releases</h2>
        <p>Sample Article URL: 
            <a href="{{ ticker_data.article_url }}" target="_blank">{{ ticker_data.article_name }}</a>
        </p>
        <p>Sample Article: {{ ticker_data.article_name }}</p>

    </div>
</div>
</body>
{% endblock %}