最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue+d3js+fastapi實(shí)現(xiàn)天氣柱狀圖折線圖餅圖的示例

 更新時(shí)間:2025年04月11日 08:27:29   作者:勘察加熊人  
本文主要介紹了vue+d3js+fastapi實(shí)現(xiàn)天氣柱狀圖折線圖餅圖的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

說(shuō)明:

vue+d3js+fastapi實(shí)現(xiàn)天氣柱狀圖折線圖餅圖

效果圖:

在這里插入圖片描述

step0:postman

1. 生成天氣數(shù)據(jù)(POST請(qǐng)求):

URL: http://localhost:8000/generate-data/?year=2024&month=3&seed=42

方法: POST

Headers:
  Content-Type: application/json

成功響應(yīng)示例:

{
    "status": "success",
    "message": "成功生成31條天氣數(shù)據(jù)",
    "year": 2024,
    "month": 3
}

2. 查詢天氣數(shù)據(jù)(GET請(qǐng)求):

URL: http://localhost:8000/weather-data/?year=2024&month=4

方法: GET

成功響應(yīng)示例:

{
    "status": "success",
    "count": 31,
    "year": 2024,
    "month": 3,
    "data": [
        {
            "record_date": "2024-03-01",
            "temperature": 16.4,
            "humidity": 72,
            "precipitation": 0.0,
            "wind_speed": 7.2,
            "weather_condition": "Cloudy"
        },
        
        {
            "record_date": "2024-03-31",
            "temperature": 17.3,
            "humidity": 62,
            "precipitation": 3.8,
            "wind_speed": 1.4,
            "weather_condition": "Rain"
        }
    ]
}

step1:sql

CREATE TABLE weather_data (
    id INT AUTO_INCREMENT PRIMARY KEY,
    record_date DATE NOT NULL,
    temperature DECIMAL(4,1) NOT NULL,  -- 格式:-99.9 到 99.9
    humidity TINYINT UNSIGNED NOT NULL,  -- 范圍:0-100
    precipitation DECIMAL(5,1) NOT NULL, -- 最大999.9mm
    wind_speed DECIMAL(4,1) NOT NULL,   -- 最大99.9m/s
    weather_condition VARCHAR(50) NOT NULL,  -- 修改列名
    INDEX (record_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

select *from weather_data;

step2:python test
C:\Users\wangrusheng\PycharmProjects\FastAPIProject1\hello.py

import random
from datetime import date
from decimal import Decimal
import calendar
import pymysql.cursors
import json
# 數(shù)據(jù)庫(kù)配置(根據(jù)實(shí)際情況修改)
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': '123456',
    'db': 'db_school',
    'charset': 'utf8mb4',
    'cursorclass': pymysql.cursors.DictCursor
}


def generate_temperature(rng, min_temp=10.0, max_temp=20.0):
    """生成溫度數(shù)據(jù)(均勻分布)"""
    temp = rng.uniform(min_temp, max_temp)
    return round(temp, 1)


def generate_humidity(rng):
    """生成濕度數(shù)據(jù)(正態(tài)分布)"""
    humidity = rng.gauss(60, 15)
    humidity = max(0, min(humidity, 100))
    return int(round(humidity))


def generate_precipitation(rng):
    """生成降水量數(shù)據(jù)(20%概率下雨)"""
    if rng.random() < 0.2:
        amount = rng.expovariate(1 / 5.0)  # 平均5mm
        amount = max(0.1, min(amount, 30.0))
        return round(amount, 1)
    return 0.0


def generate_wind_speed(rng):
    """生成風(fēng)速數(shù)據(jù)(伽馬分布)"""
    speed = rng.gammavariate(2, 2)
    speed = max(0.0, min(speed, 20.0))
    return round(speed, 1)


def get_weather_condition(temperature, precipitation, humidity, rng):
    """根據(jù)天氣參數(shù)判斷天氣狀況"""
    if precipitation > 0:
        return 'Snow' if temperature < 3.0 else 'Rain'
    if humidity >= 70:
        return 'Cloudy'
    if humidity <= 30:
        return 'Sunny'
    return rng.choice(['Partly Cloudy', 'Mostly Cloudy'])


def generate_monthly_weather_data(year, month, rng=None):
    """生成整月天氣數(shù)據(jù)"""
    if rng is None:
        rng = random.Random()

    _, num_days = calendar.monthrange(year, month)
    data = []

    for day in range(1, num_days + 1):
        record_date = date(year, month, day)
        temperature = generate_temperature(rng)
        humidity = generate_humidity(rng)
        precipitation = generate_precipitation(rng)
        wind_speed = generate_wind_speed(rng)
        condition = get_weather_condition(
            temperature, precipitation, humidity, rng
        )

        data.append({
            'record_date': record_date,
            'temperature': temperature,
            'humidity': humidity,
            'precipitation': precipitation,
            'wind_speed': wind_speed,
            'weather_condition': condition
        })

    return data


def insert_weather_data(data):
    """批量插入天氣數(shù)據(jù)到數(shù)據(jù)庫(kù)"""
    connection = pymysql.connect(**DB_CONFIG)
    try:
        with connection.cursor() as cursor:
            sql = """
                INSERT INTO weather_data 
                (record_date, temperature, humidity, precipitation, wind_speed, weather_condition)
                VALUES (%s, %s, %s, %s, %s, %s)
            """
            params = [
                (
                    d['record_date'],
                    d['temperature'],
                    d['humidity'],
                    d['precipitation'],
                    d['wind_speed'],
                    d['weather_condition']
                )
                for d in data
            ]
            cursor.executemany(sql, params)
        connection.commit()
        return len(data)
    except Exception as e:
        connection.rollback()
        raise e
    finally:
        connection.close()


def get_weather_data(year: int, month: int) -> list:
    """從數(shù)據(jù)庫(kù)獲取指定年月的天氣數(shù)據(jù)并轉(zhuǎn)換為JSON兼容格式"""
    connection = pymysql.connect(**DB_CONFIG)
    try:
        with connection.cursor() as cursor:
            sql = """
                SELECT record_date, temperature, humidity, 
                       precipitation, wind_speed, weather_condition
                FROM weather_data
                WHERE YEAR(record_date) = %s AND MONTH(record_date) = %s
                ORDER BY record_date
            """
            cursor.execute(sql, (year, month))
            results = cursor.fetchall()

            # 轉(zhuǎn)換日期和數(shù)值類(lèi)型
            for record in results:
                record['record_date'] = record['record_date'].isoformat()
                # 處理Decimal類(lèi)型(如果存在)
                for key in ['temperature', 'precipitation', 'wind_speed']:
                    if isinstance(record[key], Decimal):
                        record[key] = float(record[key])
            return results
    finally:
        connection.close()


if __name__ == '__main__':
    # 示例:生成并插入2024年4月的天氣數(shù)據(jù)
    year = 2024
    month = 4

    # 創(chuàng)建帶種子的隨機(jī)生成器(保證結(jié)果可復(fù)現(xiàn))
    rng = random.Random(42)

    try:
        # 生成模擬數(shù)據(jù)
        weather_data = generate_monthly_weather_data(year, month, rng)

        # 插入數(shù)據(jù)庫(kù)
        # inserted_count = insert_weather_data(weather_data)
        # print(f"成功插入{inserted_count}條天氣數(shù)據(jù)")
        # 獲取并打印JSON數(shù)據(jù)
        weather_json = get_weather_data(year, month)
        print(json.dumps(weather_json, indent=2, ensure_ascii=False))

    except Exception as e:
        print(f"操作失敗: {str(e)}")

step3:python fastapi
C:\Users\wangrusheng\PycharmProjects\FastAPIProject1\main.py

from fastapi import FastAPI, HTTPException, Query
from datetime import date
from decimal import Decimal
from typing import Optional
import random
import calendar
import pymysql.cursors
import json
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# CORS配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
# 數(shù)據(jù)庫(kù)配置(根據(jù)實(shí)際情況修改)
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': '123456',
    'db': 'db_school',
    'charset': 'utf8mb4',
    'cursorclass': pymysql.cursors.DictCursor
}

# 以下保持原有函數(shù)定義不變(generate_temperature、generate_humidity等)
# [原有函數(shù)定義區(qū),保持與問(wèn)題中完全相同的函數(shù)實(shí)現(xiàn)]


def generate_temperature(rng, min_temp=10.0, max_temp=20.0):
    """生成溫度數(shù)據(jù)(均勻分布)"""
    temp = rng.uniform(min_temp, max_temp)
    return round(temp, 1)


def generate_humidity(rng):
    """生成濕度數(shù)據(jù)(正態(tài)分布)"""
    humidity = rng.gauss(60, 15)
    humidity = max(0, min(humidity, 100))
    return int(round(humidity))


def generate_precipitation(rng):
    """生成降水量數(shù)據(jù)(20%概率下雨)"""
    if rng.random() < 0.2:
        amount = rng.expovariate(1 / 5.0)  # 平均5mm
        amount = max(0.1, min(amount, 30.0))
        return round(amount, 1)
    return 0.0


def generate_wind_speed(rng):
    """生成風(fēng)速數(shù)據(jù)(伽馬分布)"""
    speed = rng.gammavariate(2, 2)
    speed = max(0.0, min(speed, 20.0))
    return round(speed, 1)


def get_weather_condition(temperature, precipitation, humidity, rng):
    """根據(jù)天氣參數(shù)判斷天氣狀況"""
    if precipitation > 0:
        return 'Snow' if temperature < 3.0 else 'Rain'
    if humidity >= 70:
        return 'Cloudy'
    if humidity <= 30:
        return 'Sunny'
    return rng.choice(['Partly Cloudy', 'Mostly Cloudy'])


def generate_monthly_weather_data(year, month, rng=None):
    """生成整月天氣數(shù)據(jù)"""
    if rng is None:
        rng = random.Random()

    _, num_days = calendar.monthrange(year, month)
    data = []

    for day in range(1, num_days + 1):
        record_date = date(year, month, day)
        temperature = generate_temperature(rng)
        humidity = generate_humidity(rng)
        precipitation = generate_precipitation(rng)
        wind_speed = generate_wind_speed(rng)
        condition = get_weather_condition(
            temperature, precipitation, humidity, rng
        )

        data.append({
            'record_date': record_date,
            'temperature': temperature,
            'humidity': humidity,
            'precipitation': precipitation,
            'wind_speed': wind_speed,
            'weather_condition': condition
        })

    return data


def insert_weather_data(data):
    """批量插入天氣數(shù)據(jù)到數(shù)據(jù)庫(kù)"""
    connection = pymysql.connect(**DB_CONFIG)
    try:
        with connection.cursor() as cursor:
            sql = """
                INSERT INTO weather_data 
                (record_date, temperature, humidity, precipitation, wind_speed, weather_condition)
                VALUES (%s, %s, %s, %s, %s, %s)
            """
            params = [
                (
                    d['record_date'],
                    d['temperature'],
                    d['humidity'],
                    d['precipitation'],
                    d['wind_speed'],
                    d['weather_condition']
                )
                for d in data
            ]
            cursor.executemany(sql, params)
        connection.commit()
        return len(data)
    except Exception as e:
        connection.rollback()
        raise e
    finally:
        connection.close()


def get_weather_data(year: int, month: int) -> list:
    """從數(shù)據(jù)庫(kù)獲取指定年月的天氣數(shù)據(jù)并轉(zhuǎn)換為JSON兼容格式"""
    connection = pymysql.connect(**DB_CONFIG)
    try:
        with connection.cursor() as cursor:
            sql = """
                SELECT record_date, temperature, humidity, 
                       precipitation, wind_speed, weather_condition
                FROM weather_data
                WHERE YEAR(record_date) = %s AND MONTH(record_date) = %s
                ORDER BY record_date
            """
            cursor.execute(sql, (year, month))
            results = cursor.fetchall()

            # 轉(zhuǎn)換日期和數(shù)值類(lèi)型
            for record in results:
                record['record_date'] = record['record_date'].isoformat()
                # 處理Decimal類(lèi)型(如果存在)
                for key in ['temperature', 'precipitation', 'wind_speed']:
                    if isinstance(record[key], Decimal):
                        record[key] = float(record[key])
            return results
    finally:
        connection.close()



@app.post("/generate-data/")
async def generate_weather_data(
    year: int = Query(..., ge=2000, le=2100, description="年份"),
    month: int = Query(..., ge=1, le=12, description="月份"),
    seed: Optional[int] = Query(None, description="隨機(jī)種子(可選)")
):
    """生成并插入指定月份的天氣數(shù)據(jù)"""
    try:
        rng = random.Random(seed) if seed else random.Random()
        weather_data = generate_monthly_weather_data(year, month, rng)
        inserted_count = insert_weather_data(weather_data)
        return {
            "status": "success",
            "message": f"成功生成{inserted_count}條天氣數(shù)據(jù)",
            "year": year,
            "month": month
        }
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"數(shù)據(jù)庫(kù)操作失敗: {str(e)}")

@app.get("/weather-data/")
async def get_weather(
    year: int = Query(..., ge=2000, le=2100, description="年份"),
    month: int = Query(..., ge=1, le=12, description="月份")
):
    """獲取指定月份的天氣數(shù)據(jù)"""
    try:
        data = get_weather_data(year, month)
        return {
            "status": "success",
            "count": len(data),
            "year": year,
            "month": month,
            "data": data
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"數(shù)據(jù)查詢失敗: {str(e)}")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

step4:vue
C:\Users\wangrusheng\PycharmProjects\untitled3\src\views\Lottery.vue

<template>
  <div>
    <div class="controls">
      <input v-model.number="year" type="number" placeholder="年份">
      <input v-model.number="month" type="number" placeholder="月份" min="1" max="12">
      <button @click="fetchData">查詢</button>
      <button @click="generateData">生成數(shù)據(jù)</button>
    </div>

    <div class="charts-container">
      <div class="chart-box">
        <h3>每日溫度柱狀圖</h3>
        <div ref="barChart" class="chart"></div>
      </div>

      <div class="chart-box">
        <h3>溫度趨勢(shì)折線圖</h3>
        <div ref="lineChart" class="chart"></div>
      </div>

      <div class="chart-box">
        <h3>天氣狀況分布餅圖</h3>
        <div ref="pieChart" class="chart"></div>
      </div>
    </div>
  </div>
</template>

<script>
import * as d3 from 'd3';
import axios from 'axios';

export default {
  data() {
    return {
      weatherData: [],
      year: null,
      month: null
    };
  },
  methods: {
    async fetchData() {
      if (!this.validateInput()) return;

      try {
        const response = await axios.get('http://localhost:8000/weather-data/', {
          params: { year: this.year, month: this.month }
        });
        this.weatherData = response.data.data;
        this.redrawCharts();
      } catch (error) {
        this.handleError(error, '查詢');
      }
    },

    async generateData() {
      if (!this.validateInput()) return;

      try {
        const response = await axios.post('http://localhost:8000/generate-data/', null, {
          params: { year: this.year, month: this.month, seed: 42 },
          headers: { 'Content-Type': 'application/json' }
        });
        alert(`生成成功:${response.data.message}`);
        await this.fetchData();
      } catch (error) {
        this.handleError(error, '生成');
      }
    },

    validateInput() {
      if (!this.year || !this.month) {
        alert('請(qǐng)?zhí)顚?xiě)年份和月份');
        return false;
      }
      if (this.month < 1 || this.month > 12) {
        alert('月份必須為1-12');
        return false;
      }
      return true;
    },

    handleError(error, operation) {
      console.error(`${operation}失敗:`, error);
      alert(`${operation}失敗,請(qǐng)檢查控制臺(tái)`);
    },

    redrawCharts() {
      this.clearCharts();
      this.drawBarChart();
      this.drawLineChart();
      this.drawPieChart();
    },

    clearCharts() {
      [this.$refs.barChart, this.$refs.lineChart, this.$refs.pieChart]
        .forEach(ref => ref.innerHTML = '');
    },

    // 各圖表繪制方法(保持原有實(shí)現(xiàn),開(kāi)頭添加清除邏輯)
    // 繪制柱狀圖
    drawBarChart() {
      const margin = { top: 30, right: 30, bottom: 50, left: 60 };
      const width = 800 - margin.left - margin.right;
      const height = 400 - margin.top - margin.bottom;

      const svg = d3.select(this.$refs.barChart)
        .append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

      // 創(chuàng)建比例尺
      const x = d3.scaleBand()
        .domain(this.weatherData.map(d => d.record_date))
        .range([0, width])
        .padding(0.2);

      const y = d3.scaleLinear()
        .domain([0, d3.max(this.weatherData, d => d.temperature)])
        .range([height, 0]);

      // 添加柱狀
      svg.selectAll("rect")
        .data(this.weatherData)
        .join("rect")
          .attr("x", d => x(d.record_date))
          .attr("y", d => y(d.temperature))
          .attr("width", x.bandwidth())
          .attr("height", d => height - y(d.temperature))
          .attr("fill", "#4CAF50");

      // 添加坐標(biāo)軸
      svg.append("g")
        .attr("transform", `translate(0,${height})`)
        .call(d3.axisBottom(x).tickValues(x.domain().filter((d,i) => !(i%5))));

      svg.append("g")
        .call(d3.axisLeft(y));

      // 添加標(biāo)簽
      svg.append("text")
        .attr("transform", `translate(${width/2}, ${height + 40})`)
        .style("text-anchor", "middle")
        .text("日期");

      svg.append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 0 - margin.left)
        .attr("x",0 - (height / 2))
        .attr("dy", "1em")
        .style("text-anchor", "middle")
        .text("溫度(℃)");
    },



    // 繪制折線圖
    drawLineChart() {
      const margin = { top: 30, right: 30, bottom: 50, left: 60 };
      const width = 800 - margin.left - margin.right;
      const height = 400 - margin.top - margin.bottom;

      const svg = d3.select(this.$refs.lineChart)
        .append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

      // 創(chuàng)建比例尺
      const x = d3.scaleBand()
        .domain(this.weatherData.map(d => d.record_date))
        .range([0, width]);

      const y = d3.scaleLinear()
        .domain([d3.min(this.weatherData, d => d.temperature) - 2, d3.max(this.weatherData, d => d.temperature) + 2])
        .range([height, 0]);

      // 創(chuàng)建折線生成器
      const line = d3.line()
        .x(d => x(d.record_date) + x.bandwidth()/2)
        .y(d => y(d.temperature));

      // 繪制折線
      svg.append("path")
        .datum(this.weatherData)
        .attr("fill", "none")
        .attr("stroke", "#2196F3")
        .attr("stroke-width", 2)
        .attr("d", line);

      // 添加坐標(biāo)軸
      svg.append("g")
        .attr("transform", `translate(0,${height})`)
        .call(d3.axisBottom(x).tickValues(x.domain().filter((d,i) => !(i%5))));

      svg.append("g")
        .call(d3.axisLeft(y));
    },

    // 繪制餅圖
    drawPieChart() {
      const width = 400;
      const height = 400;
      const radius = Math.min(width, height) / 2;

      const svg = d3.select(this.$refs.pieChart)
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr('transform', `translate(${width/2},${height/2})`);

      // 統(tǒng)計(jì)天氣狀況
      const data = Array.from(
        d3.rollup(this.weatherData,
          v => v.length,
          d => d.weather_condition
        ),
        ([name, value]) => ({name, value})
      );

      // 創(chuàng)建顏色比例尺
      const color = d3.scaleOrdinal()
        .domain(data.map(d => d.name))
        .range(d3.schemeCategory10);

      // 餅圖生成器
      const pie = d3.pie()
        .value(d => d.value);

      // 弧形生成器
      const arc = d3.arc()
        .innerRadius(0)
        .outerRadius(radius);

      // 繪制扇形
      const arcs = svg.selectAll("arc")
        .data(pie(data))
        .enter()
        .append("g")
        .attr("class", "arc");

      arcs.append("path")
        .attr("d", arc)
        .attr("fill", d => color(d.data.name))
        .attr("stroke", "white")
        .style("stroke-width", "2px");

      // 添加標(biāo)簽
      arcs.append("text")
        .attr("transform", d => `translate(${arc.centroid(d)})`)
        .attr("text-anchor", "middle")
        .text(d => d.data.name);
    }


  }
};
</script>

<style>
.controls {
  padding: 1rem;
  display: flex;
  gap: 1rem;
  align-items: center;
}

.controls input {
  padding: 0.5rem;
  border: 1px solid #ddd;
  border-radius: 4px;
  width: 120px;
}

.controls button {
  padding: 0.5rem 1rem;
  background: #2196F3;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.controls button:hover {
  background: #1976D2;
}

.charts-container {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding: 2rem;
}

.chart-box {
  background: white;
  padding: 1rem;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  width: 100%;
}

.chart-box h3 {
  margin: 0 0 1rem;
  color: #333;
}

.chart {
  width: 100%;
  height: 400px;
}
</style>

end

//我是分割線
step101: old vue

下面的代碼修改:

1.年份 月份 改為可選,
2.新增兩個(gè)按鈕,查詢和添加
3.查詢和添加,需要做網(wǎng)絡(luò)請(qǐng)求
4.三個(gè)圖表 需要垂直排列

1. 生成天氣數(shù)據(jù)(POST請(qǐng)求):


URL: http://localhost:8000/generate-data/?year=2024&month=3&seed=42
方法: POST
Headers:
  Content-Type: application/json
成功響應(yīng)示例:
{
    "status": "success",
    "message": "成功生成31條天氣數(shù)據(jù)",
    "year": 2024,
    "month": 3
}

<template>
  <div class="charts-container">
    <div class="chart-box">
      <h3>每日溫度柱狀圖</h3>
      <div ref="barChart" class="chart"></div>
    </div>

    <div class="chart-box">
      <h3>溫度趨勢(shì)折線圖</h3>
      <div ref="lineChart" class="chart"></div>
    </div>

    <div class="chart-box">
      <h3>天氣狀況分布餅圖</h3>
      <div ref="pieChart" class="chart"></div>
    </div>
  </div>
</template>

<script>
import * as d3 from 'd3';
import axios from 'axios';

export default {
  data() {
    return {
      weatherData: []
    };
  },
  async mounted() {
    try {
      const response = await axios.get('http://localhost:8000/weather-data/?year=2024&month=4');
      this.weatherData = response.data.data;
      this.drawBarChart();
      this.drawLineChart();
      this.drawPieChart();
    } catch (error) {
      console.error('數(shù)據(jù)獲取失敗:', error);
    }
  },
  methods: {
    // 繪制柱狀圖
    drawBarChart() {
      const margin = { top: 30, right: 30, bottom: 50, left: 60 };
      const width = 800 - margin.left - margin.right;
      const height = 400 - margin.top - margin.bottom;

      const svg = d3.select(this.$refs.barChart)
        .append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

      // 創(chuàng)建比例尺
      const x = d3.scaleBand()
        .domain(this.weatherData.map(d => d.record_date))
        .range([0, width])
        .padding(0.2);

      const y = d3.scaleLinear()
        .domain([0, d3.max(this.weatherData, d => d.temperature)])
        .range([height, 0]);

      // 添加柱狀
      svg.selectAll("rect")
        .data(this.weatherData)
        .join("rect")
          .attr("x", d => x(d.record_date))
          .attr("y", d => y(d.temperature))
          .attr("width", x.bandwidth())
          .attr("height", d => height - y(d.temperature))
          .attr("fill", "#4CAF50");

      // 添加坐標(biāo)軸
      svg.append("g")
        .attr("transform", `translate(0,${height})`)
        .call(d3.axisBottom(x).tickValues(x.domain().filter((d,i) => !(i%5))));

      svg.append("g")
        .call(d3.axisLeft(y));

      // 添加標(biāo)簽
      svg.append("text")
        .attr("transform", `translate(${width/2}, ${height + 40})`)
        .style("text-anchor", "middle")
        .text("日期");

      svg.append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 0 - margin.left)
        .attr("x",0 - (height / 2))
        .attr("dy", "1em")
        .style("text-anchor", "middle")
        .text("溫度(℃)");
    },

    // 繪制折線圖
    drawLineChart() {
      const margin = { top: 30, right: 30, bottom: 50, left: 60 };
      const width = 800 - margin.left - margin.right;
      const height = 400 - margin.top - margin.bottom;

      const svg = d3.select(this.$refs.lineChart)
        .append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

      // 創(chuàng)建比例尺
      const x = d3.scaleBand()
        .domain(this.weatherData.map(d => d.record_date))
        .range([0, width]);

      const y = d3.scaleLinear()
        .domain([d3.min(this.weatherData, d => d.temperature) - 2, d3.max(this.weatherData, d => d.temperature) + 2])
        .range([height, 0]);

      // 創(chuàng)建折線生成器
      const line = d3.line()
        .x(d => x(d.record_date) + x.bandwidth()/2)
        .y(d => y(d.temperature));

      // 繪制折線
      svg.append("path")
        .datum(this.weatherData)
        .attr("fill", "none")
        .attr("stroke", "#2196F3")
        .attr("stroke-width", 2)
        .attr("d", line);

      // 添加坐標(biāo)軸
      svg.append("g")
        .attr("transform", `translate(0,${height})`)
        .call(d3.axisBottom(x).tickValues(x.domain().filter((d,i) => !(i%5))));

      svg.append("g")
        .call(d3.axisLeft(y));
    },

    // 繪制餅圖
    drawPieChart() {
      const width = 400;
      const height = 400;
      const radius = Math.min(width, height) / 2;

      const svg = d3.select(this.$refs.pieChart)
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr('transform', `translate(${width/2},${height/2})`);

      // 統(tǒng)計(jì)天氣狀況
      const data = Array.from(
        d3.rollup(this.weatherData,
          v => v.length,
          d => d.weather_condition
        ),
        ([name, value]) => ({name, value})
      );

      // 創(chuàng)建顏色比例尺
      const color = d3.scaleOrdinal()
        .domain(data.map(d => d.name))
        .range(d3.schemeCategory10);

      // 餅圖生成器
      const pie = d3.pie()
        .value(d => d.value);

      // 弧形生成器
      const arc = d3.arc()
        .innerRadius(0)
        .outerRadius(radius);

      // 繪制扇形
      const arcs = svg.selectAll("arc")
        .data(pie(data))
        .enter()
        .append("g")
        .attr("class", "arc");

      arcs.append("path")
        .attr("d", arc)
        .attr("fill", d => color(d.data.name))
        .attr("stroke", "white")
        .style("stroke-width", "2px");

      // 添加標(biāo)簽
      arcs.append("text")
        .attr("transform", d => `translate(${arc.centroid(d)})`)
        .attr("text-anchor", "middle")
        .text(d => d.data.name);
    }
  }
};
</script>

<style>
.charts-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
  gap: 2rem;
  padding: 2rem;
}

.chart-box {
  background: white;
  padding: 1rem;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.chart-box h3 {
  margin: 0 0 1rem;
  color: #333;
}

.chart {
  width: 100%;
  height: 400px;
}
</style>

step102:c++ 模擬數(shù)據(jù)
C:\Users\wangrusheng\source\repos\CMakeProject1\CMakeProject1\CMakeProject1.cpp

#include <iostream>
#include <random>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>

struct WeatherData {
    int day;
    double temperature;
    int humidity;
    double precipitation;
    double wind_speed;
    std::string condition;
};

// 生成溫度(可指定范圍)
double generate_temperature(std::mt19937& gen, double min_temp = 10.0, double max_temp = 20.0) {
    std::uniform_real_distribution<double> dist(min_temp, max_temp);
    return std::round(dist(gen) * 10) / 10.0; // 保留1位小數(shù)
}

// 生成濕度(正態(tài)分布)
int generate_humidity(std::mt19937& gen) {
    std::normal_distribution<double> dist(60.0, 15.0);
    double humidity = dist(gen);
    humidity = std::clamp(humidity, 0.0, 100.0);
    return static_cast<int>(std::round(humidity));
}

// 生成降水量(20%概率下雨)
double generate_precipitation(std::mt19937& gen) {
    std::bernoulli_distribution rain_dist(0.2);
    if (rain_dist(gen)) {
        std::exponential_distribution<double> amount_dist(1.0 / 5.0); // 平均5mm
        double amount = amount_dist(gen);
        amount = std::clamp(amount, 0.1, 30.0);
        return std::round(amount * 10) / 10.0; // 保留1位小數(shù)
    }
    return 0.0;
}

// 生成風(fēng)速(伽馬分布)
double generate_wind_speed(std::mt19937& gen) {
    std::gamma_distribution<double> dist(2.0, 2.0);
    double speed = dist(gen);
    speed = std::clamp(speed, 0.0, 20.0);
    return std::round(speed * 10) / 10.0; // 保留1位小數(shù)
}

// 生成天氣狀況
std::string get_condition(double temp, double precip, int humidity) {
    if (precip > 0) {
        return (temp < 3.0) ? "Snow" : "Rain";
    }

    if (humidity >= 70) return "Cloudy";
    if (humidity <= 30) return "Sunny";

    // 隨機(jī)選擇部分多云或陰天
    static std::vector<std::string> options = { "Partly Cloudy", "Mostly Cloudy" };
    std::uniform_int_distribution<int> dist(0, 1);
    std::mt19937 temp_gen(std::random_device{}());
    return options[dist(temp_gen)];
}

// 生成完整月份數(shù)據(jù)
std::vector<WeatherData> generate_april_data(std::mt19937& gen) {
    std::vector<WeatherData> data;
    for (int day = 1; day <= 30; ++day) {
        WeatherData wd;
        wd.day = day;
        wd.temperature = generate_temperature(gen);
        wd.humidity = generate_humidity(gen);
        wd.precipitation = generate_precipitation(gen);
        wd.wind_speed = generate_wind_speed(gen);
        wd.condition = get_condition(wd.temperature, wd.precipitation, wd.humidity);
        data.push_back(wd);
    }
    return data;
}

int main() {
    // 初始化隨機(jī)數(shù)生成器
    std::random_device rd;
    std::mt19937 gen(rd());

    // 生成數(shù)據(jù)
    auto weather_data = generate_april_data(gen);

    // 輸出CSV格式
    std::cout << "Day,Temperature,Humidity,Precipitation,Wind Speed,Condition\n";
    for (const auto& wd : weather_data) {
        std::cout << wd.day << ","
            << std::fixed << std::setprecision(1) << wd.temperature << "°C,"
            << wd.humidity << "%,"
            << wd.precipitation << "mm,"
            << wd.wind_speed << "m/s,"
            << wd.condition << "\n";
    }

    return 0;
}

到此這篇關(guān)于vue+d3js+fastapi實(shí)現(xiàn)天氣柱狀圖折線圖餅圖的示例的文章就介紹到這了,更多相關(guān)vue+d3js+fastapi柱狀圖折線圖餅圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

最新評(píng)論

兴安盟| 施甸县| 屏山县| 远安县| 那曲县| 桂阳县| 凤山县| 保康县| 盱眙县| 格尔木市| 沂南县| 咸丰县| 平谷区| 吉首市| 五原县| 璧山县| 葫芦岛市| 漾濞| 安溪县| 长武县| 内江市| 宝山区| 资阳市| 西藏| 三原县| 津南区| 遂溪县| 辽宁省| 牟定县| 水富县| 和硕县| 黄冈市| 黎川县| 广州市| 林州市| 大洼县| 佛坪县| 普格县| 新建县| 桦南县| 连南|