-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add area-basic implementation (9 libraries) #508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
38146f6
84cb248
92a71b7
f5d1e2b
0df3045
3461044
8864341
f99f09f
6541fd1
90ee4a3
9f72c6a
c57acb0
4dd1d0b
bfeebe5
6571a9f
cd127fa
ddf9a64
e6de0dd
66b65a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| """ | ||
| area-basic: Basic Area Chart | ||
| Library: altair | ||
| """ | ||
|
|
||
| import altair as alt | ||
| import pandas as pd | ||
|
|
||
|
|
||
| # Data | ||
| data = pd.DataFrame( | ||
| { | ||
| "month": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], | ||
| "sales": [100, 150, 130, 180, 200, 220, 195, 240, 260, 230, 280, 310], | ||
| } | ||
| ) | ||
|
|
||
| # Create chart with area and line | ||
| chart = ( | ||
| alt.Chart(data) | ||
| .mark_area(opacity=0.5, color="#306998", line={"color": "#306998", "strokeWidth": 2}) | ||
| .encode( | ||
| x=alt.X("month:Q", title="Month", axis=alt.Axis(labelFontSize=16, titleFontSize=20)), | ||
| y=alt.Y("sales:Q", title="Sales", axis=alt.Axis(labelFontSize=16, titleFontSize=20)), | ||
| ) | ||
| .properties(width=1600, height=900, title=alt.TitleParams(text="Basic Area Chart", fontSize=20)) | ||
| .configure_view(strokeWidth=0) | ||
| .configure_axis(grid=True, gridOpacity=0.3) | ||
| ) | ||
|
|
||
| # Save (1600 × 900 × 3 = 4800 × 2700) | ||
| chart.save("plot.png", scale_factor=3.0) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,164 +1,55 @@ | ||
| """ | ||
| area-basic: Basic Area Chart | ||
| Implementation for: bokeh | ||
| Variant: default | ||
| Python: 3.10+ | ||
| Library: bokeh | ||
| """ | ||
|
|
||
| from typing import TYPE_CHECKING, Optional | ||
|
|
||
| import pandas as pd | ||
| from bokeh.io import export_png | ||
| from bokeh.models import ColumnDataSource | ||
| from bokeh.plotting import figure | ||
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| from bokeh.plotting import Figure | ||
|
|
||
|
|
||
| def create_plot( | ||
| data: pd.DataFrame, | ||
| x: str, | ||
| y: str, | ||
| fill_alpha: float = 0.5, | ||
| line_color: Optional[str] = None, | ||
| title: Optional[str] = None, | ||
| x_label: Optional[str] = None, | ||
| y_label: Optional[str] = None, | ||
| width: int = 1600, | ||
| height: int = 900, | ||
| **kwargs, | ||
| ) -> "Figure": | ||
| """ | ||
| Create a basic filled area chart using bokeh. | ||
|
|
||
| A simple filled area chart showing a single data series over time or | ||
| sequential x-values. The area between the data line and the baseline | ||
| (zero) is filled with a semi-transparent color. | ||
|
|
||
| Args: | ||
| data: Input DataFrame with x and y columns | ||
| x: Column name for x-axis values | ||
| y: Column name for y-axis values | ||
| fill_alpha: Transparency of the filled area (default: 0.5) | ||
| line_color: Color of the line and fill (default: bokeh blue) | ||
| title: Chart title (optional) | ||
| x_label: Label for x-axis (optional, defaults to column name) | ||
| y_label: Label for y-axis (optional, defaults to column name) | ||
| width: Figure width in pixels (default: 1600) | ||
| height: Figure height in pixels (default: 900) | ||
| **kwargs: Additional parameters passed to figure | ||
|
|
||
| Returns: | ||
| Bokeh Figure object | ||
|
|
||
| Raises: | ||
| ValueError: If data is empty or fill_alpha is out of range | ||
| KeyError: If required columns not found | ||
|
|
||
| Example: | ||
| >>> data = pd.DataFrame({ | ||
| ... 'Month': [1, 2, 3, 4, 5, 6], | ||
| ... 'Sales': [100, 120, 90, 140, 160, 130] | ||
| ... }) | ||
| >>> fig = create_plot(data, x='Month', y='Sales', title='Monthly Sales') | ||
| """ | ||
| # Input validation | ||
| if data.empty: | ||
| raise ValueError("Data cannot be empty") | ||
|
|
||
| for col in [x, y]: | ||
| if col not in data.columns: | ||
| available = ", ".join(data.columns) | ||
| raise KeyError(f"Column '{col}' not found. Available columns: {available}") | ||
|
|
||
| if not 0 <= fill_alpha <= 1: | ||
| raise ValueError(f"fill_alpha must be between 0 and 1, got {fill_alpha}") | ||
|
|
||
| # Set default color (bokeh blue) | ||
| color = line_color or "#1f77b4" | ||
|
|
||
| # Sort data by x to ensure proper area rendering | ||
| plot_data = data[[x, y]].dropna().sort_values(by=x).reset_index(drop=True) | ||
|
|
||
| # Create ColumnDataSource | ||
| source = ColumnDataSource(data={"x": plot_data[x], "y": plot_data[y], "y0": [0] * len(plot_data)}) | ||
|
|
||
| # Create figure | ||
| p = figure( | ||
| width=width, | ||
| height=height, | ||
| title=title or "Area Chart", | ||
| x_axis_label=x_label or x, | ||
| y_axis_label=y_label or y, | ||
| toolbar_location="above", | ||
| tools="pan,wheel_zoom,box_zoom,reset,save", | ||
| **kwargs, | ||
| ) | ||
|
|
||
| # Draw the filled area from baseline (0) to y values | ||
| p.varea(x="x", y1="y0", y2="y", source=source, fill_color=color, fill_alpha=fill_alpha) | ||
|
|
||
| # Draw line on top for better visibility | ||
| p.line(x="x", y="y", source=source, line_color=color, line_width=2) | ||
|
|
||
| # Styling | ||
| p.title.text_font_size = "14pt" | ||
| p.title.align = "center" | ||
|
|
||
| # Grid styling - subtle | ||
| p.xgrid.grid_line_alpha = 0.3 | ||
| p.ygrid.grid_line_alpha = 0.3 | ||
| p.xgrid.grid_line_dash = [6, 4] | ||
| p.ygrid.grid_line_dash = [6, 4] | ||
|
|
||
| # Axis styling | ||
| p.xaxis.axis_label_text_font_size = "12pt" | ||
| p.yaxis.axis_label_text_font_size = "12pt" | ||
| p.xaxis.major_label_text_font_size = "10pt" | ||
| p.yaxis.major_label_text_font_size = "10pt" | ||
|
|
||
| return p | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| import numpy as np | ||
|
|
||
| # Sample data: Monthly website traffic over a year | ||
| np.random.seed(42) | ||
| months = list(range(1, 13)) | ||
| base_traffic = [1000, 1100, 1050, 1200, 1400, 1600, 1500, 1550, 1700, 1650, 1800, 2000] | ||
| noise = np.random.normal(0, 50, 12) | ||
| traffic = [max(0, int(b + n)) for b, n in zip(base_traffic, noise, strict=False)] | ||
|
|
||
| data = pd.DataFrame({"Month": months, "Visitors": traffic}) | ||
|
|
||
| # Create plot | ||
| fig = create_plot( | ||
| data, | ||
| x="Month", | ||
| y="Visitors", | ||
| title="Monthly Website Traffic", | ||
| x_label="Month", | ||
| y_label="Visitors (thousands)", | ||
| fill_alpha=0.5, | ||
| ) | ||
|
|
||
| # Save as PNG using webdriver-manager for automatic chromedriver | ||
| from bokeh.io import export_png | ||
| from selenium import webdriver | ||
| from selenium.webdriver.chrome.options import Options | ||
| from selenium.webdriver.chrome.service import Service | ||
| from webdriver_manager.chrome import ChromeDriverManager | ||
|
|
||
| chrome_options = Options() | ||
| chrome_options.add_argument("--headless") | ||
| chrome_options.add_argument("--no-sandbox") | ||
| chrome_options.add_argument("--disable-dev-shm-usage") | ||
|
|
||
| service = Service(ChromeDriverManager().install()) | ||
| driver = webdriver.Chrome(service=service, options=chrome_options) | ||
|
|
||
| export_png(fig, filename="plot.png", webdriver=driver) | ||
| driver.quit() | ||
| print("Plot saved to plot.png") | ||
| # Data | ||
| data = pd.DataFrame( | ||
| { | ||
| "month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], | ||
| "sales": [120, 135, 148, 162, 175, 195, 210, 198, 185, 170, 158, 190], | ||
| } | ||
| ) | ||
|
|
||
| # Create x positions for categorical months | ||
| x = list(range(len(data["month"]))) | ||
| y = data["sales"].tolist() | ||
|
|
||
| source = ColumnDataSource(data={"x": x, "y": y, "month": data["month"]}) | ||
|
|
||
| # Create figure | ||
| p = figure( | ||
| width=4800, | ||
| height=2700, | ||
| title="Monthly Sales Volume", | ||
| x_axis_label="Month", | ||
| y_axis_label="Sales ($)", | ||
| x_range=(-0.5, len(x) - 0.5), | ||
| ) | ||
|
|
||
| # Plot area (varea fills from y1 to y2) | ||
| p.varea(x="x", y1=0, y2="y", source=source, fill_alpha=0.7, fill_color="#306998") | ||
|
|
||
| # Add line on top for clearer boundary | ||
| p.line(x="x", y="y", source=source, line_width=2, line_color="#306998") | ||
|
|
||
| # Configure x-axis ticks to show month labels | ||
| p.xaxis.ticker = x | ||
| p.xaxis.major_label_overrides = dict(enumerate(data["month"])) | ||
|
|
||
| # Styling | ||
| p.title.text_font_size = "20pt" | ||
| p.xaxis.axis_label_text_font_size = "20pt" | ||
| p.yaxis.axis_label_text_font_size = "20pt" | ||
| p.xaxis.major_label_text_font_size = "16pt" | ||
| p.yaxis.major_label_text_font_size = "16pt" | ||
| p.grid.grid_line_alpha = 0.3 | ||
|
|
||
| # Save | ||
| export_png(p, filename="plot.png") | ||
|
Comment on lines
1
to
+55
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| """ | ||
| area-basic: Basic Area Chart | ||
| Library: highcharts | ||
| """ | ||
|
|
||
| import tempfile | ||
| import time | ||
| import urllib.request | ||
| from pathlib import Path | ||
|
|
||
| from highcharts_core.chart import Chart | ||
| from highcharts_core.options import HighchartsOptions | ||
| from highcharts_core.options.series.area import AreaSeries | ||
| from selenium import webdriver | ||
| from selenium.webdriver.chrome.options import Options | ||
|
|
||
|
|
||
| # Data - Monthly sales example | ||
| sales = [100, 150, 130, 180, 200, 220, 195, 240, 280, 310, 290, 350] | ||
|
|
||
| # Create chart | ||
| chart = Chart(container="container") | ||
| chart.options = HighchartsOptions() | ||
|
|
||
| # Chart configuration | ||
| chart.options.chart = { | ||
| "type": "area", | ||
| "width": 4800, | ||
| "height": 2700, | ||
| "backgroundColor": "#ffffff", | ||
| "style": {"fontFamily": "Arial, sans-serif"}, | ||
| } | ||
|
|
||
| # Title | ||
| chart.options.title = {"text": "Monthly Sales Trend", "style": {"fontSize": "48px"}} | ||
|
|
||
| # Axes | ||
| chart.options.x_axis = { | ||
| "title": {"text": "Month", "style": {"fontSize": "40px"}}, | ||
| "categories": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], | ||
| "labels": {"style": {"fontSize": "32px"}, "enabled": True}, | ||
| "gridLineWidth": 1, | ||
| "gridLineColor": "rgba(0, 0, 0, 0.1)", | ||
| "tickmarkPlacement": "on", | ||
| } | ||
|
|
||
| chart.options.y_axis = { | ||
| "title": {"text": "Sales ($)", "style": {"fontSize": "40px"}}, | ||
| "labels": {"style": {"fontSize": "32px"}}, | ||
| "gridLineWidth": 1, | ||
| "gridLineColor": "rgba(0, 0, 0, 0.1)", | ||
| } | ||
|
|
||
| # Legend | ||
| chart.options.legend = {"enabled": False} | ||
|
|
||
| # Create area series | ||
| series = AreaSeries() | ||
| series.data = sales | ||
| series.name = "Sales" | ||
| series.color = "#306998" | ||
| series.fill_opacity = 0.5 | ||
| series.line_width = 4 | ||
| series.marker = {"enabled": True, "radius": 6, "fillColor": "#306998", "lineWidth": 2, "lineColor": "#ffffff"} | ||
|
|
||
| chart.add_series(series) | ||
|
|
||
| # Download Highcharts JS | ||
| highcharts_url = "https://code.highcharts.com/highcharts.js" | ||
| with urllib.request.urlopen(highcharts_url, timeout=30) as response: | ||
| highcharts_js = response.read().decode("utf-8") | ||
|
|
||
| # Generate HTML with inline scripts | ||
| html_str = chart.to_js_literal() | ||
| html_content = f"""<!DOCTYPE html> | ||
| <html> | ||
| <head> | ||
| <meta charset="utf-8"> | ||
| <script>{highcharts_js}</script> | ||
| </head> | ||
| <body style="margin:0;"> | ||
| <div id="container" style="width: 4800px; height: 2700px;"></div> | ||
| <script>{html_str}</script> | ||
| </body> | ||
| </html>""" | ||
|
|
||
| # Write temp HTML and take screenshot | ||
| with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f: | ||
| f.write(html_content) | ||
| temp_path = f.name | ||
|
|
||
| chrome_options = Options() | ||
| chrome_options.add_argument("--headless") | ||
| chrome_options.add_argument("--no-sandbox") | ||
| chrome_options.add_argument("--disable-dev-shm-usage") | ||
| chrome_options.add_argument("--disable-gpu") | ||
| chrome_options.add_argument("--window-size=4800,2800") | ||
|
|
||
| driver = webdriver.Chrome(options=chrome_options) | ||
| driver.set_window_size(4800, 2800) | ||
| driver.get(f"file://{temp_path}") | ||
| time.sleep(5) | ||
|
|
||
| # Get the container element and screenshot it directly | ||
| container = driver.find_element("id", "container") | ||
| container.screenshot("plot.png") | ||
| driver.quit() | ||
|
|
||
| Path(temp_path).unlink() | ||
|
Comment on lines
+1
to
+109
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| """ | ||
| area-basic: Basic Area Chart | ||
| Library: letsplot | ||
| """ | ||
|
|
||
| import pandas as pd | ||
| from lets_plot import ( | ||
| LetsPlot, | ||
| aes, | ||
| element_text, | ||
| geom_area, | ||
| geom_line, | ||
| ggplot, | ||
| ggsave, | ||
| ggsize, | ||
| labs, | ||
| scale_x_continuous, | ||
| theme, | ||
| theme_minimal, | ||
| ) | ||
|
|
||
|
|
||
| LetsPlot.setup_html() | ||
|
|
||
| # Data | ||
| months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] | ||
| data = pd.DataFrame( | ||
| {"month_num": range(len(months)), "sales": [120, 135, 148, 162, 175, 195, 210, 198, 185, 170, 158, 190]} | ||
| ) | ||
|
|
||
| # Plot | ||
| plot = ( | ||
| ggplot(data, aes(x="month_num", y="sales")) | ||
| + geom_area(fill="#306998", alpha=0.5) | ||
| + geom_line(color="#306998", size=2) | ||
| + scale_x_continuous(breaks=list(range(len(months))), labels=months) | ||
| + labs(x="Month", y="Sales", title="Basic Area Chart") | ||
| + theme_minimal() | ||
| + theme(axis_title=element_text(size=20), axis_text=element_text(size=16), plot_title=element_text(size=20)) | ||
| + ggsize(1600, 900) | ||
| ) | ||
|
|
||
| # Save - scale 3x to get 4800 × 2700 px | ||
| ggsave(plot, "plot.png", path=".", scale=3) | ||
|
Comment on lines
+1
to
+44
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implementation is missing the required
create_plot()function. All plot implementations in this project must follow the standard pattern:Define a
create_plot(data: pd.DataFrame, x: str, y: str, **params)function with:TYPE_CHECKINGfor forward references)Use
if __name__ == "__main__":block for example/test codeThe current implementation has hardcoded data in the main body, which prevents the plot from being used programmatically via the API. Please restructure this to match the pattern used in existing implementations like
plots/altair/line/line-basic/default.py.